From 74e439dedeb40ba57c20f5029b005287e1cb4fa0 Mon Sep 17 00:00:00 2001 From: mkornreich <52514824+mkornreich@users.noreply.github.com> Date: Sat, 24 Oct 2026 12:50:18 -0400 Subject: [PATCH] fwk: lotus: clamp typec_safety_level in update_safety_power_limit() In LEVEL_TYPEC_1_5A the Type-C safety sub-level was incremented and decremented without bounds, while the ladder only stepped down when the counter was exactly TYPEC_SAFETY_LEVEL_0 (and only stepped up when it was exactly TYPEC_SAFETY_LEVEL_3). The hard throttle applied in LEVEL_PROCHOT cuts the battery discharge current, so the first tick after entering LEVEL_TYPEC_1_5A is usually a decrease tick: the counter goes 0 -> -1 -> -2 ... and never equals TYPEC_SAFETY_LEVEL_0 again. safety_level then never returns to LEVEL_PROCHOT, so throttle_ap(THROTTLE_OFF, THROTTLE_HARD, THROTTLE_SRC_BAT_DISCHG_CURRENT) is never called and the APU stays hard throttled (~600 MHz) until the EC resets, on AC as well as battery. Every tick, cypd_update_safety_table() also indexes the 4-entry safety_table[] with the out-of-range level and passes the result to cypd_select_pdo(); the PD controllers reject it and the EC logs "SET CCG_SELECT_REG failed" about once a second. Clamp the counter to [TYPEC_SAFETY_LEVEL_0, TYPEC_SAFETY_LEVEL_3]. Fixes: 9ff6a96cd1b8 ("fwk: 16-inch: Reduce the Type-C current once the battery exceed discharge current limit") BRANCH=fwk-tulip-29169 BUG=https://github.com/FrameworkComputer/SoftwareFirmwareIssueTracker/issues/243 TEST=Host simulation of the LEVEL_PROCHOT..LEVEL_COUNT cases. Without this change, PROCHOT followed by 20 decrease ticks leaves the ladder at LEVEL_TYPEC_1_5A with the counter at -20 and the throttle on; with it, the ladder returns to LEVEL_NORMAL and releases the throttle. 1,000,000 random ticks keep the counter within [0, 3]. Not yet built or run on hardware. Co-Authored-By: Claude Opus 5.5 --- zephyr/program/framework/lotus/src/cpu_power.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/zephyr/program/framework/lotus/src/cpu_power.c b/zephyr/program/framework/lotus/src/cpu_power.c index 48d8a6df2c..4d9228749e 100644 --- a/zephyr/program/framework/lotus/src/cpu_power.c +++ b/zephyr/program/framework/lotus/src/cpu_power.c @@ -250,12 +250,21 @@ static int update_safety_power_limit(int active_mpower) } break; case LEVEL_TYPEC_1_5A: + /* + * typec_safety_level indexes safety_table[TYPEC_SAFETY_LEVEL_COUNT] + * in cypd_update_safety_table(), so keep it in [LEVEL_0, LEVEL_3]. + * Unclamped, a decrease right after entering this level drove it + * negative: the ladder never stepped back to LEVEL_PROCHOT, so + * THROTTLE_SRC_BAT_DISCHG_CURRENT was never released. + */ if (level_increase) { - typec_safety_level++; + if (typec_safety_level < TYPEC_SAFETY_LEVEL_3) + typec_safety_level++; if (typec_safety_level == TYPEC_SAFETY_LEVEL_3) safety_level++; } else { - typec_safety_level--; + if (typec_safety_level > TYPEC_SAFETY_LEVEL_0) + typec_safety_level--; if (typec_safety_level == TYPEC_SAFETY_LEVEL_0) safety_level--; }