From e8d055661403c6d85c179ce6d0ad9a0db212f8ff Mon Sep 17 00:00:00 2001 From: Noah Santerre Date: Wed, 8 Apr 2026 09:26:10 +0200 Subject: [PATCH 1/8] 1_35W --- board/hx20/cpu_power.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/board/hx20/cpu_power.c b/board/hx20/cpu_power.c index 8b2283d1e3..da7f0dbb18 100644 --- a/board/hx20/cpu_power.c +++ b/board/hx20/cpu_power.c @@ -19,7 +19,7 @@ #define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args) #define CPRINTF(format, args...) cprintf(CC_USBCHARGE, format, ## args) -#define POWER_LIMIT_1_W 28 +#define POWER_LIMIT_1_W 35 static int pl1_watt; static int pl2_watt; From 448a451012390ffc075e18111a958a3c78558c14 Mon Sep 17 00:00:00 2001 From: Noah Santerre Date: Wed, 8 Apr 2026 13:31:01 +0200 Subject: [PATCH 2/8] 2_35W and simpler rpm to pwm function --- baseboard/fwk/fan.c | 12 ++++++------ board/hx30/board.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/baseboard/fwk/fan.c b/baseboard/fwk/fan.c index 735139e54d..4f980d4ff1 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,16 +96,16 @@ 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 */ + // FAN_HARDARE_MAX = 7100 + // Tested max : 7900 RPM on flat surface, 8800 RPM when intake blocked pct = (rpm - min) / ((FAN_HARDARE_MAX - min) / 100); /*CPRINTS(" Fan max min : %d , %d", max, min);*/ } diff --git a/board/hx30/board.h b/board/hx30/board.h index c70f79894c..517771d5d7 100644 --- a/board/hx30/board.h +++ b/board/hx30/board.h @@ -411,7 +411,7 @@ /*#define CONFIG_FAN_RPM_CUSTOM*/ #undef CONFIG_FAN_INIT_SPEED #define CONFIG_FAN_INIT_SPEED 15 -#define FAN_HARDARE_MAX 7100 +#define FAN_HARDARE_MAX 7900 #define CONFIG_TEMP_SENSOR #define CONFIG_DPTF #define CONFIG_TEMP_SENSOR_F75303 From 9e7791a3bf5e6002da3349ad8885957f4705e6db Mon Sep 17 00:00:00 2001 From: Noah Santerre Date: Wed, 8 Apr 2026 13:37:30 +0200 Subject: [PATCH 3/8] 3_cpupower accessible to ectool --- board/hx20/cpu_power.c | 19 +++++++++++++++++++ include/ec_commands.h | 14 ++++++++++++++ util/ectool.c | 21 +++++++++++++++++++++ 3 files changed, 54 insertions(+) diff --git a/board/hx20/cpu_power.c b/board/hx20/cpu_power.c index da7f0dbb18..bd28893e0e 100644 --- a/board/hx20/cpu_power.c +++ b/board/hx20/cpu_power.c @@ -14,6 +14,7 @@ #include "cypress5525.h" #include "math_util.h" #include "util.h" +#include "ec_commands.h" #define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args) @@ -143,6 +144,24 @@ static int cmd_cpupower(int argc, char **argv) return EC_SUCCESS; } + +/* Host command handler for CPU power limits */ +static enum ec_status host_command_cpu_power(struct host_cmd_handler_args *args) +{ + struct ec_response_cpu_power *r = args->response; + + /* 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_HOST_COMMAND(EC_CMD_CPU_POWER, host_command_cpu_power, EC_VER_MASK(0)); + DECLARE_CONSOLE_COMMAND(cpupower, cmd_cpupower, "cpupower pl1 pl2 pl4 psys ", "Set/Get the cpupower limit"); diff --git a/include/ec_commands.h b/include/ec_commands.h index 0cef7d2512..1c32885790 100644 --- a/include/ec_commands.h +++ b/include/ec_commands.h @@ -6968,6 +6968,20 @@ struct ec_params_charger_control { } __ec_align_size1; /*****************************************************************************/ +/* + * CPU Power command + * Get/set CPU power limits + */ +#define EC_CMD_CPU_POWER 0x03D5 + +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/util/ectool.c b/util/ectool.c index f6b6deedf2..8ac6cb0fc7 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 CPU power limits (PL1, PL2, PL4, Psys)\n" " chipinfo\n" " Prints chip info\n" " cmdversions \n" @@ -559,6 +562,23 @@ int cmd_hibdelay(int argc, char *argv[]) return 0; } +static int cmd_cpu_power(int argc, char *argv[]) +{ + struct ec_response_cpu_power r; + int rv; + + 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,6 +10135,7 @@ const struct command commands[] = { {"button", cmd_button}, {"cbi", cmd_cbi}, {"chargecurrentlimit", cmd_charge_current_limit}, + {"cpupower", cmd_cpu_power}, {"chargecontrol", cmd_charge_control}, {"chargeoverride", cmd_charge_port_override}, {"chargestate", cmd_charge_state}, From a322598df0757c91b712f116d07d8299dde14af7 Mon Sep 17 00:00:00 2001 From: Noah Santerre Date: Wed, 8 Apr 2026 14:46:20 +0200 Subject: [PATCH 4/8] 4_extended_time_window --- board/hx20/peci_customization.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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) From 944753e3c9512939fe585eaa84258b6ad5d2bd23 Mon Sep 17 00:00:00 2001 From: Noah Santerre Date: Wed, 8 Apr 2026 18:25:02 +0200 Subject: [PATCH 5/8] 5_50W_power_loud --- board/hx20/board.c | 4 ++-- board/hx20/cpu_power.c | 19 ++++++++++++++++++- include/ec_commands.h | 7 +++++++ util/ectool.c | 15 ++++++++++++++- 4 files changed, 41 insertions(+), 4 deletions(-) diff --git a/board/hx20/board.c b/board/hx20/board.c index d91ef42799..af67c312e9 100644 --- a/board/hx20/board.c +++ b/board/hx20/board.c @@ -1022,8 +1022,8 @@ static const struct ec_thermal_config thermal_inductor_cpu = { [EC_TEMP_THRESH_HIGH] = C_TO_K(68), [EC_TEMP_THRESH_HALT] = 0, }, - .temp_fan_off = C_TO_K(40), - .temp_fan_max = C_TO_K(69), + .temp_fan_off = C_TO_K(20), + .temp_fan_max = C_TO_K(60), }; static const struct ec_thermal_config thermal_inductor_ddr = { .temp_host = { diff --git a/board/hx20/cpu_power.c b/board/hx20/cpu_power.c index bd28893e0e..9358d64e87 100644 --- a/board/hx20/cpu_power.c +++ b/board/hx20/cpu_power.c @@ -20,7 +20,7 @@ #define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args) #define CPRINTF(format, args...) cprintf(CC_USBCHARGE, format, ## args) -#define POWER_LIMIT_1_W 35 +#define POWER_LIMIT_1_W 50 static int pl1_watt; static int pl2_watt; @@ -148,8 +148,25 @@ static int cmd_cpupower(int argc, char **argv) /* 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) { + if (p->pl1_mW != 0) + pl1_watt = p->pl1_mW / 1000; + if (p->pl2_mW != 0) + pl2_watt = p->pl2_mW / 1000; + if (p->pl4_mW != 0) + pl4_watt = p->pl4_mW / 1000; + if (p->psys_mW != 0) + psys_watt = p->psys_mW / 1000; + + /* Apply the new limits */ + manual_ctl = true; + set_pl_limits(pl1_watt, pl2_watt, pl4_watt, psys_watt); + } + /* Return current power limits in mW */ r->pl1_mW = pl1_watt * 1000; r->pl2_mW = pl2_watt * 1000; diff --git a/include/ec_commands.h b/include/ec_commands.h index 1c32885790..471bbb5818 100644 --- a/include/ec_commands.h +++ b/include/ec_commands.h @@ -6974,6 +6974,13 @@ struct ec_params_charger_control { */ #define EC_CMD_CPU_POWER 0x03D5 +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) */ + uint32_t psys_mW; /* Psys 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 */ diff --git a/util/ectool.c b/util/ectool.c index 8ac6cb0fc7..e0f68361ac 100644 --- a/util/ectool.c +++ b/util/ectool.c @@ -564,10 +564,23 @@ int cmd_hibdelay(int argc, char *argv[]) static int cmd_cpu_power(int argc, char *argv[]) { + struct ec_params_cpu_power p = {}; struct ec_response_cpu_power r; int rv; - rv = ec_command(EC_CMD_CPU_POWER, 0, NULL, 0, &r, sizeof(r)); + /* If arguments provided, set the values */ + if (argc >= 5) { + 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; + p.psys_mW = strtol(argv[4], 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; From 824fc472801525a1ad374f91b768691dd81926dd Mon Sep 17 00:00:00 2001 From: Noah Santerre Date: Thu, 9 Apr 2026 15:30:27 +0200 Subject: [PATCH 6/8] 6_50W_customfan --- board/hx20/board.c | 10 +++- board/hx20/cpu_power.c | 129 ++++++++++++++++++++--------------------- include/ec_commands.h | 24 +++----- util/ectool.c | 42 ++++++++------ 4 files changed, 105 insertions(+), 100 deletions(-) diff --git a/board/hx20/board.c b/board/hx20/board.c index af67c312e9..a5ff064abc 100644 --- a/board/hx20/board.c +++ b/board/hx20/board.c @@ -1022,8 +1022,8 @@ static const struct ec_thermal_config thermal_inductor_cpu = { [EC_TEMP_THRESH_HIGH] = C_TO_K(68), [EC_TEMP_THRESH_HALT] = 0, }, - .temp_fan_off = C_TO_K(20), - .temp_fan_max = C_TO_K(60), + .temp_fan_off = C_TO_K(40), + .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/cpu_power.c b/board/hx20/cpu_power.c index 9358d64e87..964f558219 100644 --- a/board/hx20/cpu_power.c +++ b/board/hx20/cpu_power.c @@ -15,6 +15,7 @@ #include "math_util.h" #include "util.h" #include "ec_commands.h" +#include "temp_sensor.h" #define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args) @@ -101,84 +102,80 @@ DECLARE_HOOK(HOOK_BATTERY_SOC_CHANGE, update_soc_power_limit_hook, HOOK_PRIO_DEF -static int cmd_cpupower(int argc, char **argv) -{ - 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); - } - } +/* Fan mode enumeration */ +enum fan_mode { + FAN_MODE_SILENT = 0, + FAN_MODE_NORMAL = 1, + FAN_MODE_EXTREME = 2, +}; - 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); +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) +{ + 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); } - return EC_SUCCESS; - + current_fan_mode = mode; } -/* Host command handler for CPU power limits */ -static enum ec_status host_command_cpu_power(struct host_cmd_handler_args *args) +/* Fan mode host command handler */ +static enum ec_status host_command_fan_mode(struct host_cmd_handler_args *args) { - const struct ec_params_cpu_power *p = args->params; - struct ec_response_cpu_power *r = args->response; + const struct ec_params_fan_mode *p = args->params; + struct ec_response_fan_mode *r = args->response; - /* If parameters provided, set the values */ + /* If params provided, set the mode */ if (args->params_size > 0 && p) { - if (p->pl1_mW != 0) - pl1_watt = p->pl1_mW / 1000; - if (p->pl2_mW != 0) - pl2_watt = p->pl2_mW / 1000; - if (p->pl4_mW != 0) - pl4_watt = p->pl4_mW / 1000; - if (p->psys_mW != 0) - psys_watt = p->psys_mW / 1000; - - /* Apply the new limits */ - manual_ctl = true; - set_pl_limits(pl1_watt, pl2_watt, pl4_watt, psys_watt); + if (p->mode <= FAN_MODE_EXTREME) { + update_thermal_params_for_mode(p->mode); + CPRINTS("Fan mode set to %d", p->mode); + } } - /* 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; - + /* Return current mode */ + r->mode = current_fan_mode; args->response_size = sizeof(*r); return EC_RES_SUCCESS; } -DECLARE_HOST_COMMAND(EC_CMD_CPU_POWER, host_command_cpu_power, EC_VER_MASK(0)); +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(cpupower, cmd_cpupower, - "cpupower pl1 pl2 pl4 psys ", - "Set/Get the cpupower limit"); +DECLARE_CONSOLE_COMMAND(fanmode, cmd_fan_mode, + "[silent|normal|extreme]", + "Set/Get fan mode"); diff --git a/include/ec_commands.h b/include/ec_commands.h index 471bbb5818..6d986e866e 100644 --- a/include/ec_commands.h +++ b/include/ec_commands.h @@ -6969,24 +6969,18 @@ struct ec_params_charger_control { /*****************************************************************************/ /* - * CPU Power command - * Get/set CPU power limits + * Fan Mode command + * Get/set fan operating mode */ -#define EC_CMD_CPU_POWER 0x03D5 +#define EC_CMD_FAN_MODE 0x03D5 -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) */ - uint32_t psys_mW; /* Psys power in milliwatts (0 = query only) */ -} __ec_align4; +struct ec_params_fan_mode { + uint8_t mode; /* 0=silent, 1=normal, 2=extreme */ +} __ec_align1; -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; +struct ec_response_fan_mode { + uint8_t mode; /* Current fan mode */ +} __ec_align1; /****************************************************************************/ /* diff --git a/util/ectool.c b/util/ectool.c index e0f68361ac..d90bbb8f3f 100644 --- a/util/ectool.c +++ b/util/ectool.c @@ -562,33 +562,41 @@ int cmd_hibdelay(int argc, char *argv[]) return 0; } -static int cmd_cpu_power(int argc, char *argv[]) +static int cmd_fan_mode(int argc, char *argv[]) { - struct ec_params_cpu_power p = {}; - struct ec_response_cpu_power r; + struct ec_params_fan_mode p = {}; + struct ec_response_fan_mode r; int rv; + const char *mode_names[] = {"silent", "normal", "extreme"}; - /* If arguments provided, set the values */ - if (argc >= 5) { - 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; - p.psys_mW = strtol(argv[4], NULL, 0) * 1000; + /* 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_CPU_POWER, 0, &p, sizeof(p), &r, sizeof(r)); + rv = ec_command(EC_CMD_FAN_MODE, 0, &p, sizeof(p), &r, sizeof(r)); } else { /* Query only */ - rv = ec_command(EC_CMD_CPU_POWER, 0, NULL, 0, &r, sizeof(r)); + rv = ec_command(EC_CMD_FAN_MODE, 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); + if (r.mode <= 2) + printf("Fan mode: %s\n", mode_names[r.mode]); + else + printf("Unknown fan mode: %d\n", r.mode); + return 0; } @@ -10148,7 +10156,7 @@ const struct command commands[] = { {"button", cmd_button}, {"cbi", cmd_cbi}, {"chargecurrentlimit", cmd_charge_current_limit}, - {"cpupower", cmd_cpu_power}, + {"fanmode", cmd_fan_mode}, {"chargecontrol", cmd_charge_control}, {"chargeoverride", cmd_charge_port_override}, {"chargestate", cmd_charge_state}, From 5baa1ff6e52261a8ba44a51e6b2d95833c911c9d Mon Sep 17 00:00:00 2001 From: Noah Santerre Date: Mon, 13 Apr 2026 11:32:51 +0200 Subject: [PATCH 7/8] Reintroduce cpupower to set PL1, PL2 and PL4 manually, or restore default values Update maximum fan speed --- baseboard/fwk/fan.c | 8 ++--- board/hx20/board.c | 6 ++-- board/hx20/board.h | 2 +- board/hx20/cpu_power.c | 79 ++++++++++++++++++++++++++++++++++-------- board/hx30/board.h | 2 +- include/ec_commands.h | 21 +++++++++++ util/ectool.c | 35 ++++++++++++++++++- 7 files changed, 129 insertions(+), 24 deletions(-) diff --git a/baseboard/fwk/fan.c b/baseboard/fwk/fan.c index 4f980d4ff1..8bf1366fe6 100644 --- a/baseboard/fwk/fan.c +++ b/baseboard/fwk/fan.c @@ -104,9 +104,9 @@ int fan_rpm_to_percent(int fan, int rpm) * if we want a performance mode we can tweak this * to get a few more % of fan speed to unlock additional * cooling TODO FRAMEWORK */ - // FAN_HARDARE_MAX = 7100 - // Tested max : 7900 RPM on flat surface, 8800 RPM when intake blocked - 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 a5ff064abc..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] = { 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 964f558219..ba1dc354ce 100644 --- a/board/hx20/cpu_power.c +++ b/board/hx20/cpu_power.c @@ -21,11 +21,23 @@ #define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args) #define CPRINTF(format, args...) cprintf(CC_USBCHARGE, format, ## args) -#define POWER_LIMIT_1_W 50 - -static int pl1_watt; -static int pl2_watt; -static int pl4_watt; +// 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 + +// 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; @@ -47,6 +59,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; @@ -72,23 +85,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); } } @@ -179,3 +192,41 @@ static int cmd_fan_mode(int argc, char **argv) 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_HOST_COMMAND(EC_CMD_CPU_POWER, host_command_cpu_power, EC_VER_MASK(0)); \ No newline at end of file diff --git a/board/hx30/board.h b/board/hx30/board.h index 517771d5d7..c70f79894c 100644 --- a/board/hx30/board.h +++ b/board/hx30/board.h @@ -411,7 +411,7 @@ /*#define CONFIG_FAN_RPM_CUSTOM*/ #undef CONFIG_FAN_INIT_SPEED #define CONFIG_FAN_INIT_SPEED 15 -#define FAN_HARDARE_MAX 7900 +#define FAN_HARDARE_MAX 7100 #define CONFIG_TEMP_SENSOR #define CONFIG_DPTF #define CONFIG_TEMP_SENSOR_F75303 diff --git a/include/ec_commands.h b/include/ec_commands.h index 6d986e866e..ef47304d26 100644 --- a/include/ec_commands.h +++ b/include/ec_commands.h @@ -6982,6 +6982,27 @@ 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 diff --git a/util/ectool.c b/util/ectool.c index d90bbb8f3f..71254b9f49 100644 --- a/util/ectool.c +++ b/util/ectool.c @@ -94,7 +94,7 @@ const char help_str[] = " chargestate\n" " Handle commands related to charge state v2 (and later)\n" " cpupower\n" - " Get CPU power limits (PL1, PL2, PL4, Psys)\n" + " Get or set CPU power limits (PL1, PL2, PL4, default)\n" " chipinfo\n" " Prints chip info\n" " cmdversions \n" @@ -129,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" @@ -600,6 +602,36 @@ static int cmd_fan_mode(int argc, char *argv[]) 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, @@ -10163,6 +10195,7 @@ const struct command commands[] = { {"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}, From f07a0a7c92235fd8af85e3ef7b51cf2fd718b509 Mon Sep 17 00:00:00 2001 From: Noah Santerre Date: Mon, 13 Apr 2026 12:02:04 +0200 Subject: [PATCH 8/8] Sets fan to auto when setting fanmode --- board/hx20/cpu_power.c | 2 ++ common/fan.c | 5 +++++ include/fan.h | 2 ++ 3 files changed, 9 insertions(+) diff --git a/board/hx20/cpu_power.c b/board/hx20/cpu_power.c index ba1dc354ce..8bef369628 100644 --- a/board/hx20/cpu_power.c +++ b/board/hx20/cpu_power.c @@ -15,6 +15,7 @@ #include "math_util.h" #include "util.h" #include "ec_commands.h" +#include "fan.h" #include "temp_sensor.h" @@ -141,6 +142,7 @@ void update_thermal_params_for_mode(enum fan_mode mode) 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 */ 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/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 */