summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaisuke Nojiri <dnojiri@chromium.org>2019-07-02 10:49:21 -0700
committerCommit Bot <commit-bot@chromium.org>2019-07-08 15:53:15 +0000
commit4c471f792a3231f6a943711d9dadf75348b5e3bf (patch)
tree98a4e738e7c3a656b45bba9c31f23ea41937b912
parentf4de8a08a0b6d222f44aa3c81bf8e7fa8f7bea2f (diff)
downloadchrome-ec-4c471f792a3231f6a943711d9dadf75348b5e3bf.tar.gz
Kefka: Implement battery probe cycle
This implements a battery probe cycle in EC autonomously. Once EC enters the cycle, it wakes up every 2 hours and checks soc and VBAT. If both are good, EC sets hibernation timer to 2 hours and sleeps again. This repeats until a power button is pressed or a battery is cut off after a battery is drained. The expected behavior can be verified as follows: 1. Shut down DUT. 2. Unplug AC and leave DUT idle for 60 min. 3. DUT hibernates. 4. DUT wakes up every 2 hours and soc is printed on EC console. 5. DUT cuts off battery when soc goes below 6%. 6. DUT boots by plugging in AC. Additionally, - Verify DUT boots when power button is pressed after #3. Signed-off-by: Daisuke Nojiri <dnojiri@chromium.org> BUG=b/128455667,b/136032811 BRANCH=strago TEST=See the description above. Change-Id: I66fd1345e5db1fc2c31bbee59edf36c3b20cab14 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1686594 Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org> Commit-Queue: Daisuke Nojiri <dnojiri@chromium.org> Tested-by: Daisuke Nojiri <dnojiri@chromium.org> Auto-Submit: Daisuke Nojiri <dnojiri@chromium.org>
-rw-r--r--board/kefka/board.h2
-rw-r--r--chip/mec1322/clock.c4
-rw-r--r--chip/mec1322/system.c111
-rw-r--r--include/clock.h6
4 files changed, 71 insertions, 52 deletions
diff --git a/board/kefka/board.h b/board/kefka/board.h
index d759fb9f56..feef164971 100644
--- a/board/kefka/board.h
+++ b/board/kefka/board.h
@@ -73,7 +73,7 @@
#define CONFIG_CHARGER_INPUT_CURRENT 3136
#define CONFIG_CHARGER_DISCHARGE_ON_AC
#define CONFIG_BATTERY_REQUESTS_NIL_WHEN_DEAD
-#define CONFIG_HIBERNATE_PERIOD (3600 * 23)
+#define CONFIG_HIBERNATE_PERIOD (60 * 60 * 2)
#define CONFIG_BATTERY_CRITICAL_SHUTDOWN_CUT_OFF
#define CONFIG_PWM
diff --git a/chip/mec1322/clock.c b/chip/mec1322/clock.c
index c5ce698b2a..cfc87c248e 100644
--- a/chip/mec1322/clock.c
+++ b/chip/mec1322/clock.c
@@ -158,7 +158,7 @@ static void system_reset_htimer_alarm(void)
* This is mec1322 specific and equivalent to ARM Cortex's
* 'DeepSleep' via system control block register, CPU_SCB_SYSCTRL
*/
-static void prepare_for_deep_sleep(void)
+void prepare_for_deep_sleep(void)
{
/* sysTick timer */
CPU_NVIC_ST_CTRL &= ~ST_ENABLE;
@@ -192,7 +192,7 @@ static void prepare_for_deep_sleep(void)
CPU_NVIC_ST_CTRL &= ~ST_TICKINT; /* SYS_TICK_INT_DISABLE */
}
-static void resume_from_deep_sleep(void)
+void resume_from_deep_sleep(void)
{
CPU_NVIC_ST_CTRL |= ST_TICKINT; /* SYS_TICK_INT_ENABLE */
CPU_NVIC_ST_CTRL |= ST_ENABLE;
diff --git a/chip/mec1322/system.c b/chip/mec1322/system.c
index 4a10e3220b..87e0bb031e 100644
--- a/chip/mec1322/system.c
+++ b/chip/mec1322/system.c
@@ -5,6 +5,8 @@
/* System module for Chrome EC : MEC1322 hardware specific implementation */
+#include "battery.h"
+#include "charge_state_v2.h"
#include "clock.h"
#include "common.h"
#include "console.h"
@@ -190,10 +192,56 @@ uint32_t system_get_scratchpad(void)
return MEC1322_VBAT_RAM(HIBDATA_INDEX_SCRATCHPAD);
}
+/*
+ * This runs in a single thread environment. Interrupts are disabled.
+ */
+static void check_battery(void)
+{
+ int battery_is_low = 0;
+ struct batt_params batt;
+ int batt_level_shutdown;
+ const struct battery_info *batt_info;
+
+ /* Gather info */
+ batt_level_shutdown = board_set_battery_level_shutdown();
+ batt_info = battery_get_info();
+ battery_get_params(&batt);
+
+ /*
+ * Check soc & VBAT.
+ *
+ * We shouldn't need to check if AC is plugged or a battery is being
+ * charged because we get here only by timer wake-up.
+ *
+ * That is, if AC is plugged, EC doesn't enter the battery probe loop.
+ * If AC is plugged after entering the loop, EC wakes up by AC instead
+ * of timer.
+ */
+ if (!(batt.flags & BATT_FLAG_BAD_STATE_OF_CHARGE) &&
+ batt.state_of_charge < batt_level_shutdown)
+ battery_is_low = 1;
+ else if (!(batt.flags & BATT_FLAG_BAD_VOLTAGE) &&
+ batt.voltage <= batt_info->voltage_min)
+ battery_is_low = 1;
+
+ CPRINTS("Battery %s (%d%%, %dmV)", battery_is_low ? "low" : "ok",
+ batt.state_of_charge, batt.voltage);
+
+ if (!battery_is_low)
+ return;
+
+ board_cut_off_battery();
+ CPRINTS("Battery cutoff");
+ /*
+ * While looping here causes WDT to trigger. So, we let rest of the
+ * code run until EC naturally loses power (as done in other places).
+ */
+}
+
void system_hibernate(uint32_t seconds, uint32_t microseconds)
{
int i;
- int htimer;
+ int htimer = 0;
CPRINTS("%s(%d, %d)", __func__, seconds, microseconds);
if (seconds || microseconds) {
@@ -214,55 +262,8 @@ void system_hibernate(uint32_t seconds, uint32_t microseconds)
if (board_hibernate)
board_hibernate();
- /* Disable interrupts */
interrupt_disable();
- for (i = 0; i <= 92; ++i) {
- task_disable_irq(i);
- task_clear_pending_irq(i);
- }
-
- for (i = 8; i <= 23; ++i)
- MEC1322_INT_DISABLE(i) = 0xffffffff;
-
- MEC1322_INT_BLK_DIS |= 0xffff00;
-
- /* Power down ADC VREF */
- MEC1322_EC_ADC_VREF_PD |= 1;
-
- /* Assert nSIO_RESET */
- MEC1322_PCR_PWR_RST_CTL |= 1;
-
- /* Disable UART */
- MEC1322_UART_ACT &= ~0x1;
- MEC1322_LPC_ACT &= ~0x1;
-
- /* Disable JTAG */
- MEC1322_EC_JTAG_EN &= ~1;
-
- /* Disable 32KHz clock */
- MEC1322_VBAT_CE &= ~0x2;
-
- /* Stop watchdog */
- MEC1322_WDG_CTL &= ~1;
-
- /* Stop timers */
- MEC1322_TMR32_CTL(0) &= ~1;
- MEC1322_TMR32_CTL(1) &= ~1;
- MEC1322_TMR16_CTL(0) &= ~1;
-
- /* Power down ADC */
- MEC1322_ADC_CTRL &= ~1;
-
- /* Disable blocks */
- MEC1322_PCR_CHIP_SLP_EN |= 0x3;
- MEC1322_PCR_EC_SLP_EN |= MEC1322_PCR_EC_SLP_EN_SLEEP;
- MEC1322_PCR_HOST_SLP_EN |= MEC1322_PCR_HOST_SLP_EN_SLEEP;
- MEC1322_PCR_EC_SLP_EN2 |= MEC1322_PCR_EC_SLP_EN2_SLEEP;
- MEC1322_PCR_SLOW_CLK_CTL &= 0xfffffc00;
-
- /* Set sleep state */
- MEC1322_PCR_SYS_SLP_CTL = (MEC1322_PCR_SYS_SLP_CTL & ~0x7) | 0x2;
- CPU_SCB_SYSCTRL |= 0x4;
+ prepare_for_deep_sleep();
/* Setup GPIOs for hibernate */
if (board_set_gpio_hibernate_state)
@@ -311,6 +312,18 @@ void system_hibernate(uint32_t seconds, uint32_t microseconds)
asm("wfi");
+ while (MEC1322_INT_SOURCE(17) & MEC1322_INT_SOURCE_HTIMER) {
+ resume_from_deep_sleep();
+ interrupt_enable();
+ check_battery();
+ cflush();
+ interrupt_disable();
+ prepare_for_deep_sleep();
+ MEC1322_HTIMER_PRELOAD = htimer;
+ MEC1322_INT_SOURCE(17) |= MEC1322_INT_SOURCE_HTIMER;
+ asm("wfi");
+ }
+
/* Use 48MHz clock to speed through wake-up */
MEC1322_PCR_PROC_CLK_CTL = 1;
diff --git a/include/clock.h b/include/clock.h
index 7702ca85eb..283afe5d63 100644
--- a/include/clock.h
+++ b/include/clock.h
@@ -101,4 +101,10 @@ void clock_disable_peripheral(uint32_t offset, uint32_t mask, uint32_t mode);
*/
void clock_refresh_console_in_use(void);
+/**
+ * Get EC ready for entering and waking from deep sleep
+ */
+void prepare_for_deep_sleep(void);
+void resume_from_deep_sleep(void);
+
#endif /* __CROS_EC_CLOCK_H */