|
| 1 | +/* Copyright 2023 The ChromiumOS Authors |
| 2 | + * Use of this source code is governed by a BSD-style license that can be |
| 3 | + * found in the LICENSE file. |
| 4 | + */ |
| 5 | + |
| 6 | +#include "chipset.h" |
| 7 | +#include "common.h" |
| 8 | +#include "console.h" |
| 9 | +#include "fan.h" |
| 10 | +#include "hooks.h" |
| 11 | +#include "system.h" |
| 12 | +#include "thermal.h" |
| 13 | +#include "temp_sensor.h" |
| 14 | +#include "util.h" |
| 15 | +#include "temperature_filter.h" |
| 16 | +#include "math_util.h" |
| 17 | +#include "temp_sensor/f75303.h" |
| 18 | +#include "temp_sensor/f75397.h" |
| 19 | + |
| 20 | +#define CPRINTS(format, args...) cprints(CC_THERMAL, format, ##args) |
| 21 | +#define CPRINTF(format, args...) cprintf(CC_THERMAL, format, ##args) |
| 22 | + |
| 23 | +#define FAN_STOP_DELAY_S (5 * SECOND) |
| 24 | + |
| 25 | + |
| 26 | +/*coeff in the form b0, b1, b2, A0, a1, a2 note: drop a0*/ |
| 27 | +/* 1590,-3130,1590,-31527,15193,14 */ |
| 28 | +/* */ |
| 29 | +const int32_t apu_coeff[6] = { |
| 30 | + 22, 44, 22, 16384, -31023, 14727 |
| 31 | +}; |
| 32 | +struct biquad apu_filtered = { |
| 33 | + .coeff = apu_coeff, |
| 34 | +}; |
| 35 | + |
| 36 | +static void board_temperature_reset(void) |
| 37 | +{ |
| 38 | + thermal_filter_reset(&apu_filtered); |
| 39 | +} |
| 40 | +DECLARE_HOOK(HOOK_CHIPSET_RESUME, board_temperature_reset, HOOK_PRIO_DEFAULT); |
| 41 | + |
| 42 | +bool log_thermal; |
| 43 | +/* battery-temp */ |
| 44 | +#define TEMP_BATTERY TEMP_SENSOR_BATTERY |
| 45 | + |
| 46 | +/* TODO: Rename to SOC */ |
| 47 | +/* soc-temp */ |
| 48 | +#define TEMP_APU TEMP_SENSOR_PECI |
| 49 | + |
| 50 | +/* ddr-f75303 */ |
| 51 | +#define TEMP_DDR TEMP_SENSOR_DDR |
| 52 | +#define TEMP_DDR_F TEMP_SENSOR_DDR |
| 53 | + |
| 54 | +/* cpu-f75303 */ |
| 55 | +#define TEMP_CPU TEMP_SENSOR_CPU |
| 56 | +#define TEMP_CPU_F TEMP_SENSOR_CPU |
| 57 | + |
| 58 | +/* local-f75397 */ |
| 59 | +#define TEMP_LOCAL TEMP_SENSOR_LOCAL |
| 60 | +#define TEMP_LOCAL_F TEMP_SENSOR_LOCAL |
| 61 | + |
| 62 | + |
| 63 | +int fan_percent_to_rpm(int fan_index, int temp_ratio) |
| 64 | +{ |
| 65 | + int rpm; |
| 66 | + int max = fans[fan_index].rpm->rpm_max; |
| 67 | + int min = fans[fan_index].rpm->rpm_min; |
| 68 | + |
| 69 | + if (temp_ratio <= 0) { |
| 70 | + rpm = 0; |
| 71 | + } else { |
| 72 | + rpm = ((temp_ratio - 1) * max + (100 - temp_ratio) * min) / 99; |
| 73 | + } |
| 74 | + |
| 75 | + return rpm; |
| 76 | +} |
| 77 | + |
| 78 | +void board_override_fan_control(int fan, int *temp) |
| 79 | +{ |
| 80 | + int actual_rpm, new_rpm; |
| 81 | + int apu_temp_mk = 0; |
| 82 | + |
| 83 | + int apu_pct = 0; |
| 84 | + int pct = 0; |
| 85 | +#ifdef CONFIG_GPU |
| 86 | + int apu_selected_pct = 0; |
| 87 | + int current_max_temp_idx = TEMP_APU; |
| 88 | +#endif |
| 89 | + int apu_filtered_temp = 0; |
| 90 | + |
| 91 | + int apu_filtered_pct = 0; |
| 92 | + int temps_mk[5] = {0}; |
| 93 | + |
| 94 | + static timestamp_t deadline; |
| 95 | + timestamp_t now = get_time(); |
| 96 | + |
| 97 | + /* |
| 98 | + * CPRINTS("fan: %d, is_thermal_control_enabled: %d", fan, is_thermal_control_enabled(fan)); |
| 99 | + * */ |
| 100 | + if (!is_thermal_control_enabled(fan)) |
| 101 | + return; |
| 102 | + |
| 103 | + /* |
| 104 | + * In common/fan.c pwm_fan_stop() will turn off fan |
| 105 | + * when chipset suspend or shutdown. |
| 106 | + */ |
| 107 | + if (chipset_in_state(CHIPSET_STATE_ON)) { |
| 108 | + |
| 109 | + if (fan == 0) { |
| 110 | + thermal_filter_update(&apu_filtered, temp[TEMP_APU]); |
| 111 | + } |
| 112 | + /*f75303_get_val_mk(TEMP_CPU_F, &apu_temp_mk); */ |
| 113 | + |
| 114 | + apu_filtered_temp = thermal_filter_get(&apu_filtered); |
| 115 | + |
| 116 | + f75303_get_val_mk(TEMP_CPU_F, &temps_mk[1]); |
| 117 | + if (thermal_params[TEMP_CPU].temp_fan_off && |
| 118 | + thermal_params[TEMP_CPU].temp_fan_max) { |
| 119 | + apu_pct = thermal_fan_percent(thermal_params[TEMP_CPU].temp_fan_off * 1000, |
| 120 | + thermal_params[TEMP_CPU].temp_fan_max * 1000, |
| 121 | + temps_mk[1]); |
| 122 | + } |
| 123 | + |
| 124 | + if (thermal_params[TEMP_APU].temp_fan_off && |
| 125 | + thermal_params[TEMP_APU].temp_fan_max) { |
| 126 | + apu_filtered_pct = thermal_fan_percent( |
| 127 | + thermal_params[TEMP_APU].temp_fan_off * 1000, |
| 128 | + thermal_params[TEMP_APU].temp_fan_max * 1000, |
| 129 | + C_TO_K(apu_filtered_temp)*1000); |
| 130 | + } |
| 131 | + pct = MAX(apu_pct, apu_filtered_pct); |
| 132 | + new_rpm = fan_percent_to_rpm(fan, pct); |
| 133 | + actual_rpm = fan_get_rpm_actual(FAN_CH(fan)); |
| 134 | + |
| 135 | + /* |
| 136 | + * If we want to turn and the fans are currently significantly below |
| 137 | + * the minimum turning speed, we should turn at least as fast as the |
| 138 | + * necessary start speed instead. |
| 139 | + */ |
| 140 | + if (new_rpm && actual_rpm < fans[fan].rpm->rpm_min * 9 / 10 && |
| 141 | + new_rpm < fans[fan].rpm->rpm_start) |
| 142 | + new_rpm = fans[fan].rpm->rpm_start; |
| 143 | + |
| 144 | + if (!new_rpm) { |
| 145 | + /* add temperature histeresis so the fan does not turn off |
| 146 | + * unless the system has cooled 0.5C below the fan turn on temperature |
| 147 | + */ |
| 148 | + if (thermal_params[TEMP_APU].temp_fan_off && |
| 149 | + apu_temp_mk > (thermal_params[TEMP_APU].temp_fan_off |
| 150 | + * 1000 - 500)) { |
| 151 | + deadline.val = get_time().val + FAN_STOP_DELAY_S; |
| 152 | + } |
| 153 | + if (!timestamp_expired(deadline, &now)) |
| 154 | + return; |
| 155 | + } else { |
| 156 | + deadline.val = get_time().val + FAN_STOP_DELAY_S; |
| 157 | + } |
| 158 | + |
| 159 | + if (log_thermal && fan == 0) { |
| 160 | + f75303_get_val_mk(TEMP_DDR_F, &temps_mk[0]); |
| 161 | + f75303_get_val_mk(TEMP_CPU_F, &temps_mk[1]); |
| 162 | + f75397_get_val_mk(TEMP_LOCAL_F, &temps_mk[2]); |
| 163 | + CPRINTS( |
| 164 | + "\tThrm\t%d\t%d\t%d\t" |
| 165 | + "\t%d\t%d\t" |
| 166 | + "\t%d\t" |
| 167 | + "\t%d\t%d\t%d\t" |
| 168 | + "\t%d\t%d", |
| 169 | + MILLI_KELVIN_TO_CELSIUS(temps_mk[0]), |
| 170 | + MILLI_KELVIN_TO_CELSIUS(temps_mk[1]), |
| 171 | + MILLI_KELVIN_TO_CELSIUS(temps_mk[2]), |
| 172 | + temp[TEMP_BATTERY], temp[TEMP_APU], |
| 173 | + thermal_filter_get(&apu_filtered), |
| 174 | + pct, apu_pct, apu_filtered_pct, |
| 175 | + new_rpm, actual_rpm); |
| 176 | + } |
| 177 | + fan_set_rpm_mode(fan, 1); |
| 178 | + fan_set_rpm_target(FAN_CH(fan), new_rpm); |
| 179 | + } else if (chipset_in_state(CHIPSET_STATE_ANY_SUSPEND)) { |
| 180 | + /* Stop fan when enter S0ix */ |
| 181 | + fan_set_rpm_mode(fan, 1); |
| 182 | + fan_set_rpm_target(fan, 0); |
| 183 | + } |
| 184 | +} |
| 185 | + |
| 186 | +/* EC console command */ |
| 187 | +static int thermallog_cmd(int argc, char **argv) |
| 188 | +{ |
| 189 | + if (argc >= 2) { |
| 190 | + if (!strncmp(argv[1], "en", 2)) { |
| 191 | + log_thermal = true; |
| 192 | + CPRINTS( |
| 193 | + "\tThrm\tDDR\tCPU\tLocal\t" |
| 194 | + "\tBAT\tSOC\t" |
| 195 | + "\tS_f\t" |
| 196 | + "\tPCT\tSpct\tSfilt\t" |
| 197 | + "\tRPM\tFAN" |
| 198 | + ); |
| 199 | + } else if (!strncmp(argv[1], "dis", 3)) { |
| 200 | + log_thermal = false; |
| 201 | + } else { |
| 202 | + return EC_ERROR_PARAM1; |
| 203 | + } |
| 204 | + } else { |
| 205 | + CPRINTS("thermallog [en/dis]"); |
| 206 | + } |
| 207 | + return EC_SUCCESS; |
| 208 | +} |
| 209 | +DECLARE_CONSOLE_COMMAND(thermallog, thermallog_cmd, "<en/dis>", |
| 210 | + "Enable or disable thermal logging"); |
| 211 | + |
0 commit comments