| // Copyright 2012 Google Inc. All Rights Reserved. |
| // Author: kedong@google.com (Ke Dong) |
| |
| #include "bruno/logging.h" |
| #include "platform.h" |
| #include "fancontrol.h" |
| #include <stdio.h> |
| #include <vector> |
| #include <string> |
| #include <sstream> |
| #include <iostream> |
| #include <string.h> |
| #include <stdint.h> |
| #include <fstream> |
| #include <unistd.h> |
| |
| namespace bruno_platform_peripheral { |
| |
| #define MAX(a,b) (((a) > (b) ? (a) : (b))) |
| |
| #define FAN_CONTROL_PARAMS_FILE "/user/sysmgr/fan_control_params.tbl" |
| |
| /* same as lm96063 spinup setting in barebox. */ |
| const unsigned int FanControl::kPwmDefaultStartup = 50; |
| const unsigned int FanControl::kPwmMinValue = 0; |
| const unsigned int FanControl::kPwmMaxValue = 100; |
| |
| const unsigned int FanControl::kFanSpeedNotSpinning = 0; |
| |
| /* |
| * Fan will start and increase speed at temp_setpt + temp_step + 1 |
| * Fan will start slowing at temp_setpt - temp_step - 1 |
| * In between, it will not change speed. |
| */ |
| |
| /* |
| * Defaults of Fan control parameters for GFMS100 (Bruno-IS) |
| * For GFMS100, Dmin and PWMsetp are used under FMS100_SOC settings. |
| */ |
| const FanControlParams FanControl::kGFMS100FanCtrlSocDefaults = { |
| temp_setpt : 90, |
| temp_max : 100, |
| temp_step : 2, |
| duty_cycle_min: 25, |
| duty_cycle_max: 100, |
| pwm_step : 1, |
| temp_overheat : 120, |
| }; |
| |
| const FanControlParams FanControl::kGFMS100FanCtrlHddDefaults = { |
| temp_setpt : 56, |
| temp_max : 60, |
| temp_step : 2, |
| duty_cycle_min: 25, |
| duty_cycle_max: 100, |
| pwm_step : 1, |
| temp_overheat : 120, |
| }; |
| |
| /* |
| * Defaults of Fan control parameters for GFRG200/210 (optimus/optimus+hdd) |
| * There is no direct SOC temp input, so we use the remote sensor. |
| * Mapping between external temp sensor and actual cpu temp was determined |
| * exterimentally. See b/14666398 spreadsheet attachment. |
| */ |
| const FanControlParams FanControl::kGFRG200FanCtrlSocDefaults = { |
| temp_setpt : 82, // fan on @ 85 (cpu =~ 93) |
| temp_max : 92, // cpu =~ 100 |
| temp_step : 2, |
| duty_cycle_min: 30, |
| duty_cycle_max: 100, |
| pwm_step : 1, |
| temp_overheat : 105, |
| }; |
| |
| const FanControlParams FanControl::kGFRG210FanCtrlSocDefaults = { |
| temp_setpt : 86, // fan on @ 89 (cpu =~ 93) |
| temp_max : 94, // cpu =~ 100 |
| temp_step : 2, |
| duty_cycle_min: 30, |
| duty_cycle_max: 100, |
| pwm_step : 1, |
| temp_overheat : 105, |
| }; |
| |
| const FanControlParams FanControl::kGFRG210FanCtrlHddDefaults = { |
| temp_setpt : 56, |
| temp_max : 60, |
| temp_step : 2, |
| duty_cycle_min: 30, |
| duty_cycle_max: 100, |
| pwm_step : 1, |
| temp_overheat : 105, |
| }; |
| /* |
| * Defaults of Fan control parameters for GFRG250 (Optimus Prime) |
| * There is no direct SOC temp input, so we use the remote sensor. |
| * Thermal policy can be found at b/23119698 |
| */ |
| |
| const FanControlParams FanControl::kGFRG250FanCtrlSocDefaults = { |
| temp_setpt : 76, |
| temp_max : 88, |
| temp_step : 3, |
| duty_cycle_min: 30, |
| duty_cycle_max: 100, |
| pwm_step : 2, |
| temp_overheat : 105, |
| }; |
| |
| const FanControlParams FanControl::kGFRG250FanCtrlHddDefaults = { |
| temp_setpt : 55, |
| temp_max : 60, |
| temp_step : 2, |
| duty_cycle_min: 30, |
| duty_cycle_max: 100, |
| pwm_step : 1, |
| temp_overheat : 105, |
| }; |
| |
| /* |
| * On Optimus Prime, AUX1 refers to the temperature sensor in the Quantenna SoC |
| * which controls the 11ac wifi interface. The granularity of the temperature |
| * readings are very coarse: increments of 5C. |
| */ |
| const FanControlParams FanControl::kGFRG250FanCtrlAux1Defaults = { |
| temp_setpt : 90, |
| temp_max : 109, /* fan speed is set to max when |
| temperatures reaches 110C */ |
| temp_step : 9, |
| duty_cycle_min: 30, |
| duty_cycle_max: 100, |
| pwm_step : 2, |
| temp_overheat : 120, |
| }; |
| |
| /* |
| * Defaults of Fan control parameters for GFSC100 (Spacecast). |
| * There is no direct SOC temp input, so we use the remote sensor. |
| * Mapping between external temp sensor and actual cpu temp was determined |
| * exterimentally. |
| */ |
| |
| const FanControlParams FanControl::kGFSC100FanCtrlSocDefaults = { |
| temp_setpt : 86, // fan on @ 89 (cpu =~ 93) |
| temp_max : 94, // cpu =~ 100 |
| temp_step : 2, |
| duty_cycle_min: 30, |
| duty_cycle_max: 100, |
| pwm_step : 1, |
| temp_overheat : 105, |
| }; |
| |
| const FanControlParams FanControl::kGFSC100FanCtrlHddDefaults = { |
| temp_setpt : 56, |
| temp_max : 60, |
| temp_step : 2, |
| duty_cycle_min: 30, |
| duty_cycle_max: 100, |
| pwm_step : 1, |
| temp_overheat : 105, |
| }; |
| /* |
| * Defaults of Fan control parameters for GFHD100 (Bruno) |
| * the original duty_cycle_min value is set to 25 |
| * but from the measurement, pwm = 25%, fan duty-cycle |
| * (or fan speed) is 45~50%. |
| * the original duty_cycle_max value is set to 100 |
| * but from the measurement, pwm = 40% or above, fan duty-cycle |
| * (or fan speed) is 99%. pwm is set to any value greater 40 |
| * it will only increase fan speed by less than 1%. |
| * Therefore Dmax is set to 40. |
| */ |
| const FanControlParams FanControl::kGFHD100FanCtrlSocDefaults = { |
| temp_setpt : 90, |
| temp_max : 100, |
| temp_step : 2, |
| duty_cycle_min: 12, |
| duty_cycle_max: 40, |
| pwm_step : 1, |
| temp_overheat : 120, |
| }; |
| |
| const FanControlParams FanControl::kGFHD200FanCtrlSocDefaults = { |
| temp_setpt : 0, /* No fan */ |
| temp_max : 0, |
| temp_step : 0, |
| duty_cycle_min: 0, |
| duty_cycle_max: 0, |
| pwm_step : 0, |
| temp_overheat : 120, |
| }; |
| |
| const FanControlParams FanControl::kGFHD254FanCtrlSocDefaults = { |
| temp_setpt : 88, |
| temp_max : 105, |
| temp_step : 3, |
| duty_cycle_min: 25, |
| duty_cycle_max: 100, |
| pwm_step : 2, |
| temp_overheat : 120, |
| }; |
| |
| /* |
| * AUX1 refers to the temperature sensor in the Quantenna SoC |
| * which controls the 11ac wifi interface. The granularity of the temperature |
| * readings are very coarse: increments of 5C. |
| */ |
| const FanControlParams FanControl::kGFHD254FanCtrlAux1Defaults = { |
| temp_setpt : 94, |
| temp_max : 110, |
| temp_step : 3, |
| duty_cycle_min: 25, |
| duty_cycle_max: 100, |
| pwm_step : 2, |
| temp_overheat : 120, |
| }; |
| |
| const FanControlParams FanControl::kGFLT110FanCtrlSocDefaults = { |
| temp_setpt : 0, /* No fan */ |
| temp_max : 0, |
| temp_step : 0, |
| duty_cycle_min: 0, |
| duty_cycle_max: 0, |
| pwm_step : 0, |
| temp_overheat : 97, |
| }; |
| |
| const FanControlParams FanControl::kGFLT300FanCtrlSocDefaults = { |
| temp_setpt : 0, /* No fan */ |
| temp_max : 0, |
| temp_step : 0, |
| duty_cycle_min: 0, |
| duty_cycle_max: 0, |
| pwm_step : 0, |
| temp_overheat : 97, |
| }; |
| |
| const FanControlParams FanControl::kGFCH100FanCtrlSocDefaults = { |
| temp_setpt : 0, /* No fan */ |
| temp_max : 0, |
| temp_step : 0, |
| duty_cycle_min: 0, |
| duty_cycle_max: 0, |
| pwm_step : 0, |
| temp_overheat : 125, |
| }; |
| |
| FanControl::~FanControl() { |
| Terminate(); |
| } |
| |
| bool FanControl::Init(bool *gpio_mailbox_ready) { |
| |
| /* Check if the platform instance has been initialized |
| * 1) If run sysmgr, the platform_ would be initalized in |
| * platformperipheral module. |
| * 2) If run test_fan test util, the platformperipheral module won't be used. |
| */ |
| |
| InitParams(); |
| |
| if (gpio_mailbox_ready != NULL) { |
| for (int loopno = 4; |
| (*gpio_mailbox_ready == false) && (loopno > 0); loopno--) { |
| sleep(2); |
| *gpio_mailbox_ready = CheckIfMailBoxIsReady(); |
| LOG(LS_VERBOSE) << "loopno=" << loopno; |
| } |
| } |
| |
| /* Get the current fan duty cycle */ |
| if (ReadFanDutyCycle(&duty_cycle_pwm_) == false) { |
| LOG(LS_ERROR) << __func__ << ": failed to get fan duty cycle"; |
| duty_cycle_pwm_ = pfan_ctrl_params_[BRUNO_SOC].duty_cycle_min; |
| } |
| LOG(LS_VERBOSE) << "duty_cycle_pwm_=" << duty_cycle_pwm_; |
| |
| /* Fan pwm has been initialized in nexus init script */ |
| return true; |
| } |
| |
| void FanControl::Terminate(void) { |
| if (pfan_ctrl_params_) { |
| delete [] pfan_ctrl_params_; |
| pfan_ctrl_params_ = NULL; |
| } |
| } |
| |
| void FanControl::InitParams() { |
| pfan_ctrl_params_ = new FanControlParams[BRUNO_PARAMS_TYPES_MAX]; |
| |
| switch (platform_->PlatformType()) { |
| case BRUNO_GFMS100: |
| /* Set thermal fan policy parameters of GFMS100 */ |
| pfan_ctrl_params_[BRUNO_SOC] = kGFMS100FanCtrlSocDefaults; |
| pfan_ctrl_params_[BRUNO_IS_HDD] = kGFMS100FanCtrlHddDefaults; |
| break; |
| case BRUNO_GFHD100: |
| /* Set thermal fan policy parameters of GFHD100 */ |
| pfan_ctrl_params_[BRUNO_SOC] = kGFHD100FanCtrlSocDefaults; |
| break; |
| case BRUNO_GFHD200: |
| pfan_ctrl_params_[BRUNO_SOC] = kGFHD200FanCtrlSocDefaults; |
| break; |
| case BRUNO_GFHD254: |
| pfan_ctrl_params_[BRUNO_SOC] = kGFHD254FanCtrlSocDefaults; |
| pfan_ctrl_params_[BRUNO_AUX1] = kGFHD254FanCtrlAux1Defaults; |
| break; |
| case BRUNO_GFRG200: |
| /* Set thermal fan policy parameters of GFRG200 */ |
| pfan_ctrl_params_[BRUNO_SOC] = kGFRG200FanCtrlSocDefaults; |
| break; |
| case BRUNO_GFRG210: |
| /* Set thermal fan policy parameters of GFRG210 */ |
| pfan_ctrl_params_[BRUNO_SOC] = kGFRG210FanCtrlSocDefaults; |
| pfan_ctrl_params_[BRUNO_IS_HDD] = kGFRG210FanCtrlHddDefaults; |
| break; |
| case BRUNO_GFRG250: |
| /* Set thermal fan policy parameters of GFRG250 */ |
| pfan_ctrl_params_[BRUNO_SOC] = kGFRG250FanCtrlSocDefaults; |
| pfan_ctrl_params_[BRUNO_IS_HDD] = kGFRG250FanCtrlHddDefaults; |
| pfan_ctrl_params_[BRUNO_AUX1] = kGFRG250FanCtrlAux1Defaults; |
| break; |
| case BRUNO_GFSC100: |
| /* Set thermal fan policy parameters of GFSC100 */ |
| pfan_ctrl_params_[BRUNO_SOC] = kGFSC100FanCtrlSocDefaults; |
| pfan_ctrl_params_[BRUNO_IS_HDD] = kGFSC100FanCtrlHddDefaults; |
| break; |
| case BRUNO_GFLT110: |
| pfan_ctrl_params_[BRUNO_SOC] = kGFLT110FanCtrlSocDefaults; |
| break; |
| case BRUNO_GFLT300: |
| pfan_ctrl_params_[BRUNO_SOC] = kGFLT300FanCtrlSocDefaults; |
| break; |
| case BRUNO_GFCH100: |
| pfan_ctrl_params_[BRUNO_SOC] = kGFCH100FanCtrlSocDefaults; |
| break; |
| case BRUNO_UNKNOWN: |
| LOG(LS_ERROR) << "Invalid platform type, ignore ... " << platform_; |
| break; |
| } |
| |
| /* Check if an external fan control parameter table existing */ |
| dbgUpdateFanControlParams(); |
| |
| /* Adjust the fan control parameters for calculation. */ |
| for (int i = 0; i < BRUNO_PARAMS_TYPES_MAX; i++) { |
| const char *suffix; |
| switch(i) { |
| case BRUNO_SOC: |
| suffix = "_SOC"; |
| break; |
| |
| case BRUNO_IS_HDD: |
| suffix = "_HDD"; |
| if (!platform_->has_hdd()) { |
| LOG(LS_INFO) << "platform does not have hdd."; |
| continue; |
| } |
| break; |
| |
| case BRUNO_AUX1: |
| suffix = "_AUX1"; |
| if (!platform_->has_aux1()) { |
| LOG(LS_INFO) << "platform does not have aux1."; |
| continue; |
| } |
| break; |
| |
| default: |
| suffix = "_UNKNOWN"; |
| LOG(LS_ERROR) << "Unknown type in fan param array"; |
| continue; |
| } |
| |
| LOG(LS_INFO) |
| << platform_->PlatformName() |
| << suffix << std::endl |
| << " Tsetpt: " << pfan_ctrl_params_[i].temp_setpt << std::endl |
| << " Tmax: " << pfan_ctrl_params_[i].temp_max << std::endl |
| << " Tstep: " << pfan_ctrl_params_[i].temp_step << std::endl |
| << " Dmin: " << pfan_ctrl_params_[i].duty_cycle_min << std::endl |
| << " Dmax: " << pfan_ctrl_params_[i].duty_cycle_max << std::endl |
| << " PWMstep: " << pfan_ctrl_params_[i].pwm_step << std::endl |
| << " Toverheat: " << pfan_ctrl_params_[i].temp_overheat << std::endl; |
| } |
| } |
| |
| |
| bool FanControl::AdjustSpeed( |
| uint16_t soc_temp, uint16_t hdd_temp, uint16_t aux1_temp, |
| uint16_t fan_speed) { |
| bool ret = true; |
| uint16_t new_duty_cycle_pwm; |
| |
| LOG(LS_VERBOSE) << __func__ << ": soc_temp=" << soc_temp |
| << " hdd_temp=" << hdd_temp << " aux1_temp=" << aux1_temp |
| << " fan_speed=" << fan_speed; |
| |
| do { |
| /* Get new SOC PWM per the current SOC and HDD temperatures */ |
| |
| /* Get new duty cycle per SOC and HDD temperatures */ |
| ComputeDutyCycle(soc_temp, hdd_temp, aux1_temp, fan_speed, |
| &new_duty_cycle_pwm); |
| |
| LOG(LS_INFO) << __func__ << ": duty_cycle_pwm = " << new_duty_cycle_pwm; |
| if (new_duty_cycle_pwm != duty_cycle_pwm_) { |
| /* When fan is not spinning and new_duty_cycle_pwm > duty_cycle_pwm_, |
| * 1) Set to higher pwm kPwmDefaultStartup for a period of time to |
| * make sure the fan starts spinning |
| * 2) then lower down to new_duty_cycle_pwm |
| */ |
| if (fan_speed == kFanSpeedNotSpinning) { |
| /* Fan is not rotating */ |
| if (new_duty_cycle_pwm > duty_cycle_pwm_) { |
| LOG(LS_INFO) << "Set higher pwm=" << kPwmDefaultStartup; |
| ret = DrivePwm(kPwmDefaultStartup); |
| if (!ret) { |
| LOG(LS_ERROR) << "DrivePwm failed" << kPwmDefaultStartup; |
| break; |
| } |
| /* Sleep before lower pwm down to new_duty_cycle_pwm */ |
| sleep(2); |
| } |
| } |
| |
| ret = DrivePwm(new_duty_cycle_pwm); |
| if (!ret) { |
| LOG(LS_ERROR) << "DrivePwm failed"; |
| break; |
| } |
| } |
| |
| } while (false); |
| |
| return ret; |
| } |
| |
| void FanControl::GetOverheatTemperature(uint16_t *poverheat_temp) { |
| FanControlParams *psoc = &pfan_ctrl_params_[BRUNO_SOC]; |
| *poverheat_temp = psoc->temp_overheat; |
| return; |
| } |
| |
| void FanControl::GetHddTemperature(uint16_t *phdd_temp) { |
| *phdd_temp = 0; |
| uint16_t hdd_temp; |
| |
| if (platform_->has_hdd() == true) { |
| std::string buf = "hdd-temperature /dev/sda"; |
| /* Create vector to hold hdd temperature words */ |
| std::vector<std::string> tokens; |
| |
| /* Insert the HDD temperature string into a stream */ |
| std::string result = ExecCmd((char *)buf.c_str(), NULL); |
| if ((result == "ERROR") || (result.empty() == true)) { |
| /* Failed to get HDD temperature. Exit */ |
| LOG(LS_ERROR) << "GetHddTemperature: Can't get HDD temperature"; |
| return; |
| } |
| std::istringstream(result) >> hdd_temp; |
| /* LOG(LS_INFO) << "hdd_temp: " << hdd_temp << std::endl; */ |
| *phdd_temp = hdd_temp; |
| } |
| return; |
| } |
| |
| bool FanControl::DrivePwm(uint16_t duty_cycle) { |
| |
| LOG(LS_INFO) << "DrivePwm = " << duty_cycle; |
| duty_cycle_pwm_ = duty_cycle; |
| |
| if (WriteFanDutyCycle(duty_cycle) == false) { |
| LOG(LS_ERROR) << "WriteFanDutyCycle failed"; |
| return false; |
| } |
| |
| if (duty_cycle == 0) { |
| state_ = OFF; |
| } else if (duty_cycle == period_+1) { |
| state_ = FULL_SPEED; |
| } else { |
| state_ = VAR_SPEED; |
| } |
| |
| return true; |
| } |
| |
| uint16_t FanControl::__ComputeDutyCycle( |
| uint16_t temp, |
| uint16_t fan_speed, |
| const FanControlParams ¶ms) { |
| |
| uint16_t compute_duty_cycle = duty_cycle_pwm_; |
| if (temp > params.temp_max) { |
| compute_duty_cycle = params.duty_cycle_max; |
| } |
| else if (temp > (params.temp_setpt + params.temp_step)) { |
| if (fan_speed == kFanSpeedNotSpinning) { |
| compute_duty_cycle = params.duty_cycle_min; |
| } |
| else if (duty_cycle_pwm_ < params.duty_cycle_max) { |
| /* 1. Possibly, the fan still stops due to duty_cycle_pwm_ is not large |
| * enough. Continue increase the duty cycle. |
| * 2. Or the fan is running, but it's not fast enough to cool down |
| * the unit. |
| */ |
| compute_duty_cycle = duty_cycle_pwm_ + params.pwm_step; |
| if (compute_duty_cycle > params.duty_cycle_max) |
| compute_duty_cycle = params.duty_cycle_max; |
| } |
| } |
| else if (temp < (params.temp_setpt - params.temp_step)) { |
| if ((fan_speed == kFanSpeedNotSpinning) || |
| (duty_cycle_pwm_ < params.pwm_step)) { |
| compute_duty_cycle = kPwmMinValue; |
| } |
| else { |
| /* Reduce fan pwm if temp is lower than |
| * the (temp_setpt - temp_step) and plus fan is still spinning |
| */ |
| compute_duty_cycle = duty_cycle_pwm_ - params.pwm_step; |
| } |
| } |
| return compute_duty_cycle; |
| } |
| |
| void FanControl::ComputeDutyCycle( |
| uint16_t soc_temp, |
| uint16_t hdd_temp, |
| uint16_t aux1_temp, |
| uint16_t fan_speed, |
| uint16_t *new_duty_cycle_pwm) { |
| |
| uint16_t soc_compute_duty_cycle = 0; |
| uint16_t hdd_compute_duty_cycle = 0; |
| uint16_t aux1_compute_duty_cycle = 0; |
| FanControlParams *psoc = &pfan_ctrl_params_[BRUNO_SOC]; |
| FanControlParams *phdd = get_hdd_fan_ctrl_parms(); |
| FanControlParams *paux1 = get_aux1_fan_ctrl_parms(); |
| |
| LOG(LS_VERBOSE) << __func__ << " - duty_cycle_pwm_ = " << duty_cycle_pwm_ |
| << " i/p soc_temp=" << soc_temp |
| << " hdd_temp=" << hdd_temp |
| << " aux1_temp=" << aux1_temp |
| << " fan_speed=" << fan_speed; |
| |
| /* check SOC temps */ |
| if (psoc) { |
| soc_compute_duty_cycle = __ComputeDutyCycle(soc_temp, fan_speed, *psoc); |
| } |
| |
| /* check HDD temps */ |
| if (phdd) { |
| hdd_compute_duty_cycle = __ComputeDutyCycle(hdd_temp, fan_speed, *phdd); |
| } |
| |
| /* check HDD temps */ |
| if (paux1) { |
| aux1_compute_duty_cycle = __ComputeDutyCycle(aux1_temp, fan_speed, *paux1); |
| } |
| |
| LOG(LS_INFO) << "soc_duty_cycle_pwm = " << soc_compute_duty_cycle << " " |
| << "hdd_duty_cycle_pwm = " << hdd_compute_duty_cycle << " " |
| << "aux1_duty_cycle_pwm = " << aux1_compute_duty_cycle; |
| |
| *new_duty_cycle_pwm = MAX(soc_compute_duty_cycle, hdd_compute_duty_cycle); |
| *new_duty_cycle_pwm = MAX(*new_duty_cycle_pwm, aux1_compute_duty_cycle); |
| |
| LOG(LS_INFO) << "new_duty_cycle_pwm = " << *new_duty_cycle_pwm; |
| |
| return; |
| } |
| |
| |
| std::string FanControl::ExecCmd(char* cmd, std::string *pattern) { |
| char buffer[256]; |
| std::string result = ""; |
| FILE* pipe = popen(cmd, "r"); |
| |
| if (!pipe) { |
| LOG(LS_ERROR) << __func__ << ": ERROR"; |
| return "ERROR"; |
| } |
| |
| while(!feof(pipe)) { |
| if(fgets(buffer, sizeof(buffer), pipe) != NULL) { |
| /* pattern == NULL, read and return all of lines |
| * pattern != NULL, return the line if found the pattern in the line |
| */ |
| if (pattern != NULL) { |
| result = buffer; |
| if (result.compare(0, pattern->size(), *pattern) == 0) { |
| break; /* Found the pattern. Exit. */ |
| } |
| result.clear(); |
| } |
| else { |
| result += buffer; |
| } |
| } |
| } |
| pclose(pipe); |
| |
| return result; |
| } |
| |
| FanControlParams *FanControl::get_hdd_fan_ctrl_parms() { |
| if (platform_->has_hdd() == true) { |
| return &pfan_ctrl_params_[BRUNO_IS_HDD]; |
| } |
| return NULL; |
| } |
| |
| FanControlParams *FanControl::get_aux1_fan_ctrl_parms() { |
| if (platform_->has_aux1() == true) { |
| return &pfan_ctrl_params_[BRUNO_AUX1]; |
| } |
| return NULL; |
| } |
| |
| |
| void FanControl::dbgUpdateFanControlParams(void) { |
| /* Check if the external fan control parameter table existing */ |
| std::ifstream params_table_file (FAN_CONTROL_PARAMS_FILE); |
| if (params_table_file.is_open()) { |
| LOG(LS_INFO) << FAN_CONTROL_PARAMS_FILE << " existing..."; |
| dbgGetFanControlParamsFromParamsFile(BRUNO_SOC); |
| if (platform_->has_hdd() == true) { |
| dbgGetFanControlParamsFromParamsFile(BRUNO_IS_HDD); |
| } |
| } |
| } |
| |
| /* A debugging function: Allow hardware engineers to tune the fan |
| * control parameters |
| */ |
| bool FanControl::dbgGetFanControlParamsFromParamsFile(uint8_t fc_idx) { |
| /* Create vector to hold hdd temperature words */ |
| std::vector<std::string> tokens; |
| uint16_t max, min; |
| |
| /* TODO - Use protobuf to parse the fan control parameters. */ |
| |
| /* Get the search platform keyword in the table file: GFMS100_SOC, |
| * GFMS100_HDD... |
| */ |
| std::string buf = platform_->PlatformName(); |
| switch (fc_idx) { |
| case BRUNO_SOC: |
| buf += "_SOC"; |
| break; |
| case BRUNO_IS_HDD: |
| buf += "_HDD"; |
| break; |
| case BRUNO_AUX1: |
| buf += "_AUX1"; |
| break; |
| default: |
| buf += "_UNKNOWN"; |
| LOG(LS_WARNING) << "Invalid fc_index: " << fc_idx << std::endl; |
| break; |
| } |
| |
| LOG(LS_INFO) << buf << std::endl; |
| |
| std::string result = platform_->GetLine((char *)FAN_CONTROL_PARAMS_FILE, &buf); |
| if (result.empty() == true) |
| return false; |
| |
| /* Insert the fan control parameters string into a stream */ |
| std::stringstream ss(result); |
| while (ss >> buf) { |
| tokens.push_back(buf); |
| } |
| |
| /* LOG(LS_INFO) << "token.size = " << tokens.size() << std::endl; */ |
| |
| /* Each line in the fan control table must have 7 elements */ |
| if (tokens.size() < 7) { |
| LOG(LS_ERROR) << __func__ << "Incorrect number of params -->" << tokens.size() ; |
| return false; /* Incorrect length. Exit. */ |
| } |
| |
| /* Compare Tsetpt and Tmax */ |
| std::istringstream(tokens.at(1)) >> min; |
| std::istringstream(tokens.at(2)) >> max; |
| if (min > max) { |
| LOG(LS_ERROR) << __func__ << "Incorrect Tsettp: " << min << " and Tmax: " << max; |
| return false; /* Invalid. Exit */ |
| } |
| |
| std::istringstream(tokens.at(4)) >> min; |
| std::istringstream(tokens.at(5)) >> max; |
| if (min > max) { |
| LOG(LS_ERROR) << __func__ << "Dmin: " << min << " and Dmax: " << max; |
| return false; /* Invalid. Exit */ |
| } |
| |
| std::istringstream(tokens.at(1)) >> pfan_ctrl_params_[fc_idx].temp_setpt; |
| std::istringstream(tokens.at(2)) >> pfan_ctrl_params_[fc_idx].temp_max; |
| std::istringstream(tokens.at(3)) >> pfan_ctrl_params_[fc_idx].temp_step; |
| std::istringstream(tokens.at(4)) >> pfan_ctrl_params_[fc_idx].duty_cycle_min; |
| std::istringstream(tokens.at(5)) >> pfan_ctrl_params_[fc_idx].duty_cycle_max; |
| std::istringstream(tokens.at(6)) >> pfan_ctrl_params_[fc_idx].pwm_step; |
| return true; |
| } |
| |
| } // namespace bruno_platform_peripheral |