diff --git a/baseboard/fwk/fan.c b/baseboard/fwk/fan.c index 735139e54d..8bf1366fe6 100644 --- a/baseboard/fwk/fan.c +++ b/baseboard/fwk/fan.c @@ -45,7 +45,7 @@ #define FAN_PID_I_INV 100 #define FAN_PID_I_MAX (10*FAN_PID_I_INV) -#define STABLE_RPM 2200 +#define STABLE_RPM 4500 static int rpm_setting[FAN_CH_COUNT]; static int duty_setting[FAN_CH_COUNT]; @@ -96,17 +96,17 @@ int fan_rpm_to_percent(int fan, int rpm) if (rpm <= STABLE_RPM) { pct = rpm / 100; return pct; - } else if (rpm <= 4000) - min = 1040 + (28 * ((rpm - STABLE_RPM) / 100)); - else if (rpm <= 5200) - min = 1040 + (20 * ((rpm - STABLE_RPM) / 100)); - + } + min = 1718; + // min = STABLE_RPM*(10000-FAN_HARDARE_MAX)/(10000-STABLE_RPM) /* make formula More in line with the actual-fan speed - * Note that this will limit the fan % to about 94% * if we want a performance mode we can tweak this * to get a few more % of fan speed to unlock additional * cooling TODO FRAMEWORK */ - pct = (rpm - min) / ((FAN_HARDARE_MAX - min) / 100); + // original FAN_HARDARE_MAX = 7100 + // Tested max : 7400 RPM on flat surface, 8500 RPM when intake blocked + pct = (rpm - min) / ((max - min) / 100); /*CPRINTS(" Fan max min : %d , %d", max, min);*/ } /*CPRINTS(" Fan PCT = %d ", pct);*/ @@ -185,7 +185,7 @@ void fan_set_rpm_target(int ch, int rpm) rpm_setting[ch] = rpm; if (chipset_in_state(CHIPSET_STATE_ON) && rpm == 0 && !timestamp_expired(fan_spindown_time, NULL)) { - rpm = 1200; + rpm = fans[0].rpm->rpm_min; } pct = fan_rpm_to_percent(ch, rpm); diff --git a/board/hx20/board.c b/board/hx20/board.c index d91ef42799..7821d5fd05 100644 --- a/board/hx20/board.c +++ b/board/hx20/board.c @@ -973,9 +973,9 @@ const struct fan_conf fan_conf_0 = { /* Default */ const struct fan_rpm fan_rpm_0 = { - .rpm_min = 1800, - .rpm_start = 1800, - .rpm_max = 6800, /* Todo: Derate by -7% so all units have same performance */ + .rpm_min = 1200, + .rpm_start = 1200, + .rpm_max = 7400, }; const struct fan_t fans[FAN_CH_COUNT] = { @@ -1023,7 +1023,7 @@ static const struct ec_thermal_config thermal_inductor_cpu = { [EC_TEMP_THRESH_HALT] = 0, }, .temp_fan_off = C_TO_K(40), - .temp_fan_max = C_TO_K(69), + .temp_fan_max = C_TO_K(75), }; static const struct ec_thermal_config thermal_inductor_ddr = { .temp_host = { @@ -1073,6 +1073,10 @@ static const struct ec_thermal_config thermal_cpu = { struct ec_thermal_config thermal_params[TEMP_SENSOR_COUNT]; BUILD_ASSERT(ARRAY_SIZE(thermal_params) == TEMP_SENSOR_COUNT); + +/* Forward declaration for fan mode initialization */ +extern void update_thermal_params_for_mode(int mode); + static void setup_fans(void) { thermal_params[TEMP_SENSOR_LOCAL] = thermal_inductor_local; @@ -1082,6 +1086,8 @@ static void setup_fans(void) #ifdef CONFIG_PECI thermal_params[TEMP_SENSOR_PECI] = thermal_cpu; #endif + /* Initialize with normal fan mode */ + update_thermal_params_for_mode(1); } DECLARE_HOOK(HOOK_INIT, setup_fans, HOOK_PRIO_DEFAULT); #endif diff --git a/board/hx20/board.h b/board/hx20/board.h index 747f81b8bb..473ccdab7a 100644 --- a/board/hx20/board.h +++ b/board/hx20/board.h @@ -394,7 +394,7 @@ #define CONFIG_FANS 1 #undef CONFIG_FAN_INIT_SPEED #define CONFIG_FAN_INIT_SPEED 15 -#define FAN_HARDARE_MAX 7100 +#define FAN_HARDARE_MAX 7400 #define CONFIG_TEMP_SENSOR #define CONFIG_DPTF #define CONFIG_TEMP_SENSOR_F75303 diff --git a/board/hx20/cpu_power.c b/board/hx20/cpu_power.c index 8b2283d1e3..8bef369628 100644 --- a/board/hx20/cpu_power.c +++ b/board/hx20/cpu_power.c @@ -14,16 +14,31 @@ #include "cypress5525.h" #include "math_util.h" #include "util.h" +#include "ec_commands.h" +#include "fan.h" +#include "temp_sensor.h" #define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args) #define CPRINTF(format, args...) cprintf(CC_USBCHARGE, format, ## args) -#define POWER_LIMIT_1_W 28 +// Loaded on EC reset +#define POWER_LIMIT_1_W_DEFAULT 40 +#define POWER_LIMIT_2_W_DEFAULT 64 +#define POWER_LIMIT_4_W_DEFAULT 121 -static int pl1_watt; -static int pl2_watt; -static int pl4_watt; +// Loaded by ectool command "cpupower default" +#define POWER_LIMIT_1_W_USER_DEFAULT 28 +#define POWER_LIMIT_2_W_USER_DEFAULT 64 +#define POWER_LIMIT_4_W_USER_DEFAULT 121 + +static int POWER_LIMIT_1_W = POWER_LIMIT_1_W_DEFAULT; +static int POWER_LIMIT_2_W = POWER_LIMIT_2_W_DEFAULT; +static int POWER_LIMIT_4_W = POWER_LIMIT_4_W_DEFAULT; + +static int pl1_watt = POWER_LIMIT_1_W_DEFAULT; +static int pl2_watt = POWER_LIMIT_2_W_DEFAULT; +static int pl4_watt = POWER_LIMIT_4_W_DEFAULT; static int psys_watt; bool manual_ctl; @@ -45,6 +60,7 @@ void update_soc_power_limit(bool force_update, bool force_no_adapter) int pps_power_budget; int battery_percent; + static int old_pl1_watt = -1; static int old_pl2_watt = -1; static int old_pl4_watt = -1; static int old_psys_watt = -1; @@ -70,23 +86,23 @@ void update_soc_power_limit(bool force_update, bool force_no_adapter) psys_watt = ((active_power * 95) / 100) - pps_power_budget; } else { /* ADP > 55W and Battery percentage >= 30% */ - pl2_watt = 64; - pl4_watt = 121; + pl1_watt = POWER_LIMIT_1_W; + pl2_watt = POWER_LIMIT_2_W; + pl4_watt = POWER_LIMIT_4_W; /* psys watt = adp watt * 0.95 + battery watt(55 W) * 0.7 - pps power budget */ psys_watt = ((active_power * 95) / 100) + 39 - pps_power_budget; } if (pl2_watt != old_pl2_watt || pl4_watt != old_pl4_watt || - psys_watt != old_psys_watt || force_update) { + psys_watt != old_psys_watt || force_update || + pl1_watt != old_pl1_watt) { + old_pl1_watt = pl1_watt; old_psys_watt = psys_watt; old_pl4_watt = pl4_watt; old_pl2_watt = pl2_watt; - pl1_watt = POWER_LIMIT_1_W; - if (manual_ctl == false) { - CPRINTS("Updating SOC Power Limits: PL2 %d, PL4 %d, Psys %d, Adapter %d", - pl2_watt, pl4_watt, psys_watt, active_power); - set_pl_limits(pl1_watt, pl2_watt, pl4_watt, psys_watt); - } + CPRINTS("Updating SOC Power Limits: PL1 %d, PL2 %d, PL4 %d, Psys %d, Adapter %d", + pl1_watt, pl2_watt, pl4_watt, psys_watt, active_power); + set_pl_limits(pl1_watt, pl2_watt, pl4_watt, psys_watt); } } @@ -100,49 +116,119 @@ DECLARE_HOOK(HOOK_BATTERY_SOC_CHANGE, update_soc_power_limit_hook, HOOK_PRIO_DEF -static int cmd_cpupower(int argc, char **argv) +/* Fan mode enumeration */ +enum fan_mode { + FAN_MODE_SILENT = 0, + FAN_MODE_NORMAL = 1, + FAN_MODE_EXTREME = 2, +}; + +static enum fan_mode current_fan_mode = FAN_MODE_NORMAL; + +/* Update thermal params based on fan mode */ +void update_thermal_params_for_mode(enum fan_mode mode) { - uint32_t pl1, pl2, pl4, psys; - char *e; - - CPRINTF("SOC Power Limit: PL1 %d, PL2 %d, PL4 %d, Psys %d\n", - pl1_watt, pl2_watt, pl4_watt, psys_watt); - if (argc >= 2) { - if (!strncmp(argv[1], "auto", 4)) { - manual_ctl = false; - CPRINTF("Auto Control"); - update_soc_power_limit(false, false); - } - if (!strncmp(argv[1], "manual", 6)) { - manual_ctl = true; - CPRINTF("Manual Control"); - set_pl_limits(pl1_watt, pl2_watt, pl4_watt, psys_watt); + extern struct ec_thermal_config thermal_params[TEMP_SENSOR_COUNT]; + + if (mode == FAN_MODE_SILENT) { + thermal_params[TEMP_SENSOR_CPU].temp_fan_off = C_TO_K(50); + thermal_params[TEMP_SENSOR_CPU].temp_fan_max = C_TO_K(85); + } else if (mode == FAN_MODE_EXTREME) { + thermal_params[TEMP_SENSOR_CPU].temp_fan_off = C_TO_K(20); + thermal_params[TEMP_SENSOR_CPU].temp_fan_max = C_TO_K(58); + } else { + /* NORMAL mode (default) */ + thermal_params[TEMP_SENSOR_CPU].temp_fan_off = C_TO_K(40); + thermal_params[TEMP_SENSOR_CPU].temp_fan_max = C_TO_K(69); + } + current_fan_mode = mode; + fan_set_thermal_control_enabled(0, 1); /* Re-enable thermal control to apply new settings */ +} + +/* Fan mode host command handler */ +static enum ec_status host_command_fan_mode(struct host_cmd_handler_args *args) +{ + const struct ec_params_fan_mode *p = args->params; + struct ec_response_fan_mode *r = args->response; + + /* If params provided, set the mode */ + if (args->params_size > 0 && p) { + if (p->mode <= FAN_MODE_EXTREME) { + update_thermal_params_for_mode(p->mode); + CPRINTS("Fan mode set to %d", p->mode); } } - if (argc >= 5) { - pl1 = strtoi(argv[1], &e, 0); - if (*e) - return EC_ERROR_PARAM1; - pl2 = strtoi(argv[2], &e, 0); - if (*e) - return EC_ERROR_PARAM2; - pl4 = strtoi(argv[3], &e, 0); - if (*e) - return EC_ERROR_PARAM3; - psys = strtoi(argv[4], &e, 0); - if (*e) - return EC_ERROR_PARAM4; - pl1_watt = pl1; - pl2_watt = pl2; - pl4_watt = pl4; - psys_watt = psys; - set_pl_limits(pl1_watt, pl2_watt, pl4_watt, psys_watt); + /* Return current mode */ + r->mode = current_fan_mode; + args->response_size = sizeof(*r); + return EC_RES_SUCCESS; +} +DECLARE_HOST_COMMAND(EC_CMD_FAN_MODE, host_command_fan_mode, EC_VER_MASK(0)); + +/* Console command for fan mode */ +static int cmd_fan_mode(int argc, char **argv) +{ + const char *mode_names[] = {"silent", "normal", "extreme"}; + int mode; + + if (argc > 1) { + if (!strcasecmp(argv[1], "silent")) + mode = FAN_MODE_SILENT; + else if (!strcasecmp(argv[1], "normal")) + mode = FAN_MODE_NORMAL; + else if (!strcasecmp(argv[1], "extreme")) + mode = FAN_MODE_EXTREME; + else { + CPRINTS("Invalid mode. Use: silent, normal, or extreme"); + return EC_ERROR_PARAM1; + } + update_thermal_params_for_mode(mode); } + + CPRINTS("Current fan mode: %s", mode_names[current_fan_mode]); return EC_SUCCESS; +} +DECLARE_CONSOLE_COMMAND(fanmode, cmd_fan_mode, + "[silent|normal|extreme]", + "Set/Get fan mode"); + +/* Host command handler for CPU power limits */ +static enum ec_status host_command_cpu_power(struct host_cmd_handler_args *args) +{ + const struct ec_params_cpu_power *p = args->params; + struct ec_response_cpu_power *r = args->response; + + /* If parameters provided, set the values */ + if (args->params_size > 0 && p) { + /* + * "default" from ectool is encoded as an all-zero payload. + */ + if (p->pl1_mW == 0 && p->pl2_mW == 0 && p->pl4_mW == 0) { + POWER_LIMIT_1_W = POWER_LIMIT_1_W_USER_DEFAULT; + POWER_LIMIT_2_W = POWER_LIMIT_2_W_USER_DEFAULT; + POWER_LIMIT_4_W = POWER_LIMIT_4_W_USER_DEFAULT; + } else { + if (p->pl1_mW != 0) + POWER_LIMIT_1_W = p->pl1_mW / 1000; + if (p->pl2_mW != 0) + POWER_LIMIT_2_W = p->pl2_mW / 1000; + if (p->pl4_mW != 0) + POWER_LIMIT_4_W = p->pl4_mW / 1000; + } + update_soc_power_limit(true, false); + } + + /* Return current power limits in mW */ + r->pl1_mW = pl1_watt * 1000; + r->pl2_mW = pl2_watt * 1000; + r->pl4_mW = pl4_watt * 1000; + r->psys_mW = psys_watt * 1000; + + args->response_size = sizeof(*r); + return EC_RES_SUCCESS; } -DECLARE_CONSOLE_COMMAND(cpupower, cmd_cpupower, - "cpupower pl1 pl2 pl4 psys ", - "Set/Get the cpupower limit"); + +DECLARE_HOST_COMMAND(EC_CMD_CPU_POWER, host_command_cpu_power, EC_VER_MASK(0)); \ No newline at end of file diff --git a/board/hx20/peci_customization.h b/board/hx20/peci_customization.h index 7f759ceeaf..0d72038665 100644 --- a/board/hx20/peci_customization.h +++ b/board/hx20/peci_customization.h @@ -30,7 +30,7 @@ #define PECI_INDEX_POWER_LIMITS_PL1 0x1A #define PECI_PARAMS_POWER_LIMITS_PL1 0x0000 -#define PECI_PL1_CONTROL_TIME_WINDOWS (0xDC << 16) /* 28 seconds */ +#define PECI_PL1_CONTROL_TIME_WINDOWS (0xFF << 16) /* 28 seconds */ #define PECI_PL1_POWER_LIMIT_ENABLE (0x01 << 15) #define PECI_PL1_POWER_LIMIT(x) (x << 3) @@ -42,7 +42,7 @@ #define PECI_INDEX_POWER_LIMITS_PSYS_PL2 0x3B #define PECI_PARAMS_POWER_LIMITS_PSYS_PL2 0x0000 -#define PECI_PSYS_PL2_CONTROL_TIME_WINDOWS (0xDC << 16) /* 28 seconds */ +#define PECI_PSYS_PL2_CONTROL_TIME_WINDOWS (0xFF << 16) /* 28 seconds */ #define PECI_PSYS_PL2_POWER_LIMIT_ENABLE (0x01 << 15) #define PECI_PSYS_PL2_POWER_LIMIT(x) (x << 3) diff --git a/common/fan.c b/common/fan.c index cee5388a3a..b426cfb9ed 100644 --- a/common/fan.c +++ b/common/fan.c @@ -121,6 +121,11 @@ test_export_static void set_thermal_control_enabled(int fan, int enable) fan_set_rpm_mode(FAN_CH(fan), 1); } +void fan_set_thermal_control_enabled(int fan, int enable) +{ + set_thermal_control_enabled(fan, enable); +} + static void set_duty_cycle(int fan, int percent) { /* Move the fan to manual control */ diff --git a/include/ec_commands.h b/include/ec_commands.h index 0cef7d2512..ef47304d26 100644 --- a/include/ec_commands.h +++ b/include/ec_commands.h @@ -6968,6 +6968,42 @@ struct ec_params_charger_control { } __ec_align_size1; /*****************************************************************************/ +/* + * Fan Mode command + * Get/set fan operating mode + */ +#define EC_CMD_FAN_MODE 0x03D5 + +struct ec_params_fan_mode { + uint8_t mode; /* 0=silent, 1=normal, 2=extreme */ +} __ec_align1; + +struct ec_response_fan_mode { + uint8_t mode; /* Current fan mode */ +} __ec_align1; + +/*****************************************************************************/ +/* + * CPU Power command + * Get/set CPU power limits + */ +#define EC_CMD_CPU_POWER 0x03D6 + +struct ec_params_cpu_power { + uint32_t pl1_mW; /* PL1 power in milliwatts (0 = query only) */ + uint32_t pl2_mW; /* PL2 power in milliwatts (0 = query only) */ + uint32_t pl4_mW; /* PL4 power in milliwatts (0 = query only) */ +} __ec_align4; + +struct ec_response_cpu_power { + uint32_t pl1_mW; /* Current PL1 in mW */ + uint32_t pl2_mW; /* Current PL2 in mW */ + uint32_t pl4_mW; /* Current PL4 in mW */ + uint32_t psys_mW; /* Current Psys in mW */ +} __ec_align4; + + +/****************************************************************************/ /* * Reserve a range of host commands for board-specific, experimental, or * special purpose features. These can be (re)used without updating this file. diff --git a/include/fan.h b/include/fan.h index fd49649547..0a947b150b 100644 --- a/include/fan.h +++ b/include/fan.h @@ -124,6 +124,8 @@ int fan_get_count(void); void fan_set_count(int count); +void fan_set_thermal_control_enabled(int fan, int enable); + int is_thermal_control_enabled(int idx); #endif /* __CROS_EC_FAN_H */ diff --git a/util/ectool.c b/util/ectool.c index f6b6deedf2..71254b9f49 100644 --- a/util/ectool.c +++ b/util/ectool.c @@ -21,6 +21,7 @@ #include "chipset.h" #include "compile_time_macros.h" #include "cros_ec_dev.h" +#include "ec_commands.h" #include "ec_panicinfo.h" #include "ec_flash.h" #include "ec_version.h" @@ -92,6 +93,8 @@ const char help_str[] = " Overrides charge port selection logic\n" " chargestate\n" " Handle commands related to charge state v2 (and later)\n" + " cpupower\n" + " Get or set CPU power limits (PL1, PL2, PL4, default)\n" " chipinfo\n" " Prints chip info\n" " cmdversions \n" @@ -126,6 +129,8 @@ const char help_str[] = " Set the maximum external power limit\n" " fanduty \n" " Forces the fan PWM to a constant duty cycle\n" + " fanmode [mode]\n" + " Prints or sets fan curve profile\n" " flasherase \n" " Erases EC flash\n" " flasheraseasync \n" @@ -559,6 +564,74 @@ int cmd_hibdelay(int argc, char *argv[]) return 0; } +static int cmd_fan_mode(int argc, char *argv[]) +{ + struct ec_params_fan_mode p = {}; + struct ec_response_fan_mode r; + int rv; + const char *mode_names[] = {"silent", "normal", "extreme"}; + + /* If argument provided, set the mode */ + if (argc > 1) { + char *mode_str = argv[1]; + if (!strcasecmp(mode_str, "silent")) + p.mode = 0; + else if (!strcasecmp(mode_str, "normal")) + p.mode = 1; + else if (!strcasecmp(mode_str, "extreme")) + p.mode = 2; + else { + printf("Invalid mode. Use: silent, normal, or extreme\n"); + return -1; + } + + rv = ec_command(EC_CMD_FAN_MODE, 0, &p, sizeof(p), &r, sizeof(r)); + } else { + /* Query only */ + rv = ec_command(EC_CMD_FAN_MODE, 0, NULL, 0, &r, sizeof(r)); + } + + if (rv < 0) + return rv; + + if (r.mode <= 2) + printf("Fan mode: %s\n", mode_names[r.mode]); + else + printf("Unknown fan mode: %d\n", r.mode); + + return 0; +} + +static int cmd_cpu_power(int argc, char *argv[]) +{ + struct ec_params_cpu_power p = {}; + struct ec_response_cpu_power r; + int rv; + + /* A default reset is encoded as an all-zero payload. */ + if (argc == 2 && !strcasecmp(argv[1], "default")) { + rv = ec_command(EC_CMD_CPU_POWER, 0, &p, sizeof(p), &r, sizeof(r)); + } else if (argc >= 4) { + p.pl1_mW = strtol(argv[1], NULL, 0) * 1000; + p.pl2_mW = strtol(argv[2], NULL, 0) * 1000; + p.pl4_mW = strtol(argv[3], NULL, 0) * 1000; + rv = ec_command(EC_CMD_CPU_POWER, 0, &p, sizeof(p), &r, sizeof(r)); + } else { + /* Query only */ + rv = ec_command(EC_CMD_CPU_POWER, 0, NULL, 0, &r, sizeof(r)); + } + + if (rv < 0) + return rv; + + printf("CPU Power Limits:\n"); + printf(" PL1: %u W\n", r.pl1_mW / 1000); + printf(" PL2: %u W\n", r.pl2_mW / 1000); + printf(" PL4: %u W\n", r.pl4_mW / 1000); + printf(" Psys: %u W\n", r.psys_mW / 1000); + return 0; +} + static void cmd_hostevent_help(char *cmd) { fprintf(stderr, @@ -10115,12 +10188,14 @@ const struct command commands[] = { {"button", cmd_button}, {"cbi", cmd_cbi}, {"chargecurrentlimit", cmd_charge_current_limit}, + {"fanmode", cmd_fan_mode}, {"chargecontrol", cmd_charge_control}, {"chargeoverride", cmd_charge_port_override}, {"chargestate", cmd_charge_state}, {"chipinfo", cmd_chipinfo}, {"cmdversions", cmd_cmdversions}, {"console", cmd_console}, + {"cpupower", cmd_cpu_power}, {"cec", cmd_cec}, {"echash", cmd_ec_hash}, {"eventclear", cmd_host_event_clear},