From bf62593ebd4dead8553ca5615290fe372198e846 Mon Sep 17 00:00:00 2001 From: Philip Chen Date: Tue, 3 Apr 2018 15:10:01 -0700 Subject: [PATCH] charge_state_v2: Throttle AP in high battery discharge current When EC sees discharge current hit BAT_MAX_DISCHG_CURRENT, we kick off a timer and ask AP to throttle. Then EC keeps monitoring discharge current. If the current doesn't drop below BAT_MAX_DISCHG_CURRENT - BAT_OCP_HYSTERESIS, we restart the timer and notify AP again, which shouldn't happen unless AP misses or ignores the first notification. When the timer expires, which means EC hasn't seen over-current for BAT_OCP_TIMEOUT_US, we ask AP to stop throttling. BUG=b:74321682, chromium:838754 BRANCH=scarlet TEST=manually test on scarlet, confirm EC sends EC_HOST_EVENT_THROTTLE_START and EC_HOST_EVENT_THROTTLE_STOP host events when entering/exiting OCP. Change-Id: I1e55fc23249596d8afec52a3885655ca9c1f2151 Signed-off-by: Philip Chen Reviewed-on: https://chromium-review.googlesource.com/994188 Commit-Ready: Philip Chen Tested-by: Philip Chen Reviewed-by: Daisuke Nojiri Reviewed-by: Matthias Kaehlcke --- common/build.mk | 1 + common/charge_state_v2.c | 44 ++++++++++++++++++++++++++++++++++++++++ include/config.h | 11 ++++++++-- include/throttle_ap.h | 6 ++++-- 4 files changed, 58 insertions(+), 4 deletions(-) diff --git a/common/build.mk b/common/build.mk index a48880bafc..1dd7801455 100644 --- a/common/build.mk +++ b/common/build.mk @@ -107,6 +107,7 @@ common-$(CONFIG_SW_CRC)+=crc.o common-$(CONFIG_TABLET_MODE)+=tablet_mode.o common-$(CONFIG_TEMP_SENSOR)+=temp_sensor.o common-$(CONFIG_THROTTLE_AP)+=thermal.o throttle_ap.o +common-$(CONFIG_THROTTLE_AP_ON_BAT_DISCHG_CURRENT)+=throttle_ap.o common-$(CONFIG_TPM_I2CS)+=i2cs_tpm.o common-$(CONFIG_TPM_LOGGING)+=event_log.o tpm_log.o common-$(CONFIG_U2F)+=u2f.o diff --git a/common/charge_state_v2.c b/common/charge_state_v2.c index 514e3add92..958257ea71 100644 --- a/common/charge_state_v2.c +++ b/common/charge_state_v2.c @@ -25,6 +25,7 @@ #include "printf.h" #include "system.h" #include "task.h" +#include "throttle_ap.h" #include "timer.h" #include "util.h" @@ -41,6 +42,20 @@ #define PRECHARGE_TIMEOUT_US (PRECHARGE_TIMEOUT * SECOND) #define LFCC_EVENT_THRESH 5 /* Full-capacity change reqd for host event */ +#ifdef CONFIG_THROTTLE_AP_ON_BAT_DISCHG_CURRENT +#ifndef CONFIG_HOSTCMD_EVENTS +#error "CONFIG_THROTTLE_AP_ON_BAT_DISCHG_CURRENT needs CONFIG_HOSTCMD_EVENTS" +#endif /* CONFIG_HOSTCMD_EVENTS */ +#define BAT_OCP_TIMEOUT_US (60 * SECOND) +/* BAT_OCP_HYSTERESIS_PCT can be optionally overridden in board.h. */ +#ifndef BAT_OCP_HYSTERESIS_PCT +#define BAT_OCP_HYSTERESIS_PCT 10 +#endif /* BAT_OCP_HYSTERESIS_PCT */ +#define BAT_OCP_HYSTERESIS \ + (BAT_MAX_DISCHG_CURRENT * BAT_OCP_HYSTERESIS_PCT / 100) /* mA */ +static timestamp_t ocp_throttle_start_time; +#endif /* CONFIG_THROTTLE_AP_ON_BAT_DISCHG_CURRENT */ + static int charge_request(int voltage, int current); /* @@ -1326,6 +1341,33 @@ static void set_charge_state(enum charge_state_v2 state) curr.state = state; } +static void notify_host_of_over_current(struct batt_params *batt) +{ +#ifdef CONFIG_THROTTLE_AP_ON_BAT_DISCHG_CURRENT + if (batt->flags & BATT_FLAG_BAD_CURRENT) + return; + + if ((!ocp_throttle_start_time.val && + (batt->current < -BAT_MAX_DISCHG_CURRENT)) || + (ocp_throttle_start_time.val && + (batt->current < -BAT_MAX_DISCHG_CURRENT + BAT_OCP_HYSTERESIS))) { + ocp_throttle_start_time = get_time(); + throttle_ap(THROTTLE_ON, THROTTLE_SOFT, + THROTTLE_SRC_BAT_DISCHG_CURRENT); + } else if (ocp_throttle_start_time.val && + (get_time().val > ocp_throttle_start_time.val + + BAT_OCP_TIMEOUT_US)) { + /* + * Clear the timer and notify AP to stop throttling if + * we haven't seen over current for BAT_OCP_TIMEOUT_US. + */ + ocp_throttle_start_time.val = 0; + throttle_ap(THROTTLE_OFF, THROTTLE_SOFT, + THROTTLE_SRC_BAT_DISCHG_CURRENT); + } +#endif +} + const struct batt_params *charger_current_battery_params(void) { return &curr.batt; @@ -1500,6 +1542,8 @@ void charger_task(void *u) curr.batt.flags |= BATT_FLAG_BAD_STATE_OF_CHARGE; } + notify_host_of_over_current(&curr.batt); + /* * Now decide what we want to do about it. We'll normally just * pass along whatever the battery wants to the charger. Note diff --git a/include/config.h b/include/config.h index 83a9dbf7df..6abf748912 100644 --- a/include/config.h +++ b/include/config.h @@ -2616,6 +2616,13 @@ /* Compile common code for throttling the CPU based on the temp sensors */ #undef CONFIG_THROTTLE_AP + +/* + * Throttle the CPU when battery discharge current is too high. When + * this feature is enabled, BAT_MAX_DISCHG_CURRENT must be defined in board.h. + */ +#undef CONFIG_THROTTLE_AP_ON_BAT_DISCHG_CURRENT + /* * If defined, dptf is enabled to manage thermals. * @@ -3416,8 +3423,8 @@ /******************************************************************************/ /* - * Throttle AP must have temperature sensor enabled to get the readings for - * thermal throttling. + * Thermal throttling AP must have temperature sensor enabled to get + * the temperature readings. */ #if defined(CONFIG_THROTTLE_AP) && !defined(CONFIG_TEMP_SENSOR) #define CONFIG_TEMP_SENSOR diff --git a/include/throttle_ap.h b/include/throttle_ap.h index 8d2af51db9..db651c432e 100644 --- a/include/throttle_ap.h +++ b/include/throttle_ap.h @@ -30,7 +30,7 @@ enum throttle_type { */ enum throttle_sources { THROTTLE_SRC_THERMAL = 0, - THROTTLE_SRC_POWER, + THROTTLE_SRC_BAT_DISCHG_CURRENT, }; /** @@ -43,7 +43,9 @@ enum throttle_sources { * @param type Type of throttling desired * @param source Which task is requesting throttling */ -#ifdef CONFIG_TEMP_SENSOR +#if defined(CONFIG_THROTTLE_AP) || \ + defined(CONFIG_THROTTLE_AP_ON_BAT_DISCHG_CURRENT) + void throttle_ap(enum throttle_level level, enum throttle_type type, enum throttle_sources source);