diff options
author | Daisuke Nojiri <dnojiri@chromium.org> | 2019-07-02 10:49:21 -0700 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2019-07-08 15:53:15 +0000 |
commit | 4c471f792a3231f6a943711d9dadf75348b5e3bf (patch) | |
tree | 98a4e738e7c3a656b45bba9c31f23ea41937b912 | |
parent | f4de8a08a0b6d222f44aa3c81bf8e7fa8f7bea2f (diff) | |
download | chrome-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.h | 2 | ||||
-rw-r--r-- | chip/mec1322/clock.c | 4 | ||||
-rw-r--r-- | chip/mec1322/system.c | 111 | ||||
-rw-r--r-- | include/clock.h | 6 |
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 */ |