mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-12-30 18:41:11 +00:00
stm32f0: low power idle task
Add low power idle task to stm32f0. This can be enabled by defining CONFIG_LOW_POWER_IDLE. This low power idle uses STOP mode to conserve power. BUG=chrome-os-partner:31226, chrome-os-partner:28335 BRANCH=none TEST=add #define CONFIG_LOW_POWER_IDLE to samus and use idlestats console command to verify using deep sleep. also #define CONFIG_FORCE_CONSOLE_RESUME and make sure serial console works without problems when going into deep sleep. Change-Id: I76b0ceb8587a139faa74353d3d8efb4f689fc669 Signed-off-by: Alec Berg <alecaberg@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/218956 Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
This commit is contained in:
committed by
chrome-internal-fetch
parent
33fe8c5b5f
commit
cf4abddca8
@@ -11,17 +11,46 @@
|
||||
#include "console.h"
|
||||
#include "cpu.h"
|
||||
#include "hooks.h"
|
||||
#include "hwtimer.h"
|
||||
#include "registers.h"
|
||||
#include "system.h"
|
||||
#include "task.h"
|
||||
#include "timer.h"
|
||||
#include "util.h"
|
||||
|
||||
/* Console output macros */
|
||||
#define CPUTS(outstr) cputs(CC_CLOCK, outstr)
|
||||
#define CPRINTS(format, args...) cprints(CC_CLOCK, format, ## args)
|
||||
|
||||
/* use 48Mhz USB-synchronized High-speed oscillator */
|
||||
#define HSI48_CLOCK 48000000
|
||||
|
||||
/* use PLL at 38.4MHz as system clock. */
|
||||
#define PLL_CLOCK 38400000
|
||||
|
||||
/* Low power idle statistics */
|
||||
#ifdef CONFIG_LOW_POWER_IDLE
|
||||
static int idle_sleep_cnt;
|
||||
static int idle_dsleep_cnt;
|
||||
static uint64_t idle_dsleep_time_us;
|
||||
static int dsleep_recovery_margin_us = 1000000;
|
||||
|
||||
/*
|
||||
* minimum delay to enter stop mode
|
||||
* STOP_MODE_LATENCY: max time to wake up from STOP mode with regulator in low
|
||||
* power mode is 5 us + PLL locking time is 200us.
|
||||
* SET_RTC_MATCH_DELAY: max time to set RTC match alarm. if we set the alarm
|
||||
* in the past, it will never wake up and cause a watchdog.
|
||||
*/
|
||||
#if (CPU_CLOCK == PLL_CLOCK)
|
||||
#define STOP_MODE_LATENCY 300 /* us */
|
||||
#else
|
||||
#define STOP_MODE_LATENCY 50 /* us */
|
||||
#endif
|
||||
#define SET_RTC_MATCH_DELAY 200 /* us */
|
||||
|
||||
#endif /* CONFIG_LOW_POWER_IDLE */
|
||||
|
||||
/*
|
||||
* RTC clock frequency (connected to LSI clock)
|
||||
*
|
||||
@@ -31,7 +60,7 @@
|
||||
* high-precision delays based solely on LSI.
|
||||
*/
|
||||
/*
|
||||
* Set synchronous clock freq to HSI/2 (20kHz) to maximize subsecond
|
||||
* Set synchronous clock freq to LSI/2 (20kHz) to maximize subsecond
|
||||
* resolution. Set asynchronous clock to 1 Hz.
|
||||
*/
|
||||
#define RTC_FREQ (40000 / 2) /* Hz */
|
||||
@@ -78,7 +107,6 @@ static inline uint32_t sec_to_rtc(uint32_t sec)
|
||||
return rtc;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Return time diff between two rtc readings */
|
||||
static inline int32_t get_rtc_diff(uint32_t rtc0, uint32_t rtc0ss,
|
||||
uint32_t rtc1, uint32_t rtc1ss)
|
||||
@@ -93,7 +121,6 @@ static inline int32_t get_rtc_diff(uint32_t rtc0, uint32_t rtc0ss,
|
||||
|
||||
return (diff < 0) ? (diff + 10*SECOND) : diff;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void rtc_read(uint32_t *rtc, uint32_t *rtcss)
|
||||
{
|
||||
@@ -169,26 +196,8 @@ void __rtc_alarm_irq(void)
|
||||
}
|
||||
DECLARE_IRQ(STM32_IRQ_RTC_WAKEUP, __rtc_alarm_irq, 1);
|
||||
|
||||
int clock_get_freq(void)
|
||||
static void config_hispeed_clock(void)
|
||||
{
|
||||
return CPU_CLOCK;
|
||||
}
|
||||
|
||||
void clock_enable_module(enum module_id module, int enable)
|
||||
{
|
||||
}
|
||||
|
||||
void clock_init(void)
|
||||
{
|
||||
/*
|
||||
* The initial state :
|
||||
* SYSCLK from HSI (=8MHz), no divider on AHB, APB1, APB2
|
||||
* PLL unlocked, RTC enabled on LSE
|
||||
*/
|
||||
|
||||
/* put 1 Wait-State for flash access to ensure proper reads at 48Mhz */
|
||||
STM32_FLASH_ACR = 0x1001; /* 1 WS / Prefetch enabled */
|
||||
|
||||
/* Ensure that HSI48 is ON */
|
||||
if (!(STM32_RCC_CR2 & (1 << 17))) {
|
||||
/* Enable HSI */
|
||||
@@ -247,6 +256,119 @@ void clock_init(void)
|
||||
#else
|
||||
#error "CPU_CLOCK must be either 48MHz or 38.4MHz"
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_LOW_POWER_IDLE
|
||||
|
||||
void clock_refresh_console_in_use(void)
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FORCE_CONSOLE_RESUME
|
||||
#define UARTN_BASE STM32_USART_BASE(CONFIG_UART_CONSOLE)
|
||||
static void enable_serial_wakeup(int enable)
|
||||
{
|
||||
if (enable)
|
||||
/*
|
||||
* Allow UART wake up from STOP mode. Note, UART clock must
|
||||
* be HSI(8MHz) for wakeup to work.
|
||||
*/
|
||||
STM32_USART_CR1(UARTN_BASE) |= STM32_USART_CR1_UESM;
|
||||
else
|
||||
/* Disable wake up from STOP mode. */
|
||||
STM32_USART_CR1(UARTN_BASE) &= ~STM32_USART_CR1_UESM;
|
||||
}
|
||||
#else
|
||||
static void enable_serial_wakeup(int enable)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
void __idle(void)
|
||||
{
|
||||
timestamp_t t0;
|
||||
int next_delay, margin_us, rtc_diff;
|
||||
uint32_t rtc0, rtc0ss, rtc1, rtc1ss;
|
||||
|
||||
while (1) {
|
||||
asm volatile("cpsid i");
|
||||
|
||||
t0 = get_time();
|
||||
next_delay = __hw_clock_event_get() - t0.le.lo;
|
||||
|
||||
if (DEEP_SLEEP_ALLOWED &&
|
||||
(next_delay > (STOP_MODE_LATENCY + SET_RTC_MATCH_DELAY))) {
|
||||
/* deep-sleep in STOP mode */
|
||||
idle_dsleep_cnt++;
|
||||
|
||||
enable_serial_wakeup(1);
|
||||
|
||||
/* set deep sleep bit */
|
||||
CPU_SCB_SYSCTRL |= 0x4;
|
||||
|
||||
set_rtc_alarm(0, next_delay - STOP_MODE_LATENCY,
|
||||
&rtc0, &rtc0ss);
|
||||
asm("wfi");
|
||||
|
||||
CPU_SCB_SYSCTRL &= ~0x4;
|
||||
|
||||
enable_serial_wakeup(0);
|
||||
|
||||
/*
|
||||
* By default only HSI 8MHz is enabled here. Re-enable
|
||||
* high-speed clock if in use.
|
||||
*/
|
||||
config_hispeed_clock();
|
||||
|
||||
/* fast forward timer according to RTC counter */
|
||||
reset_rtc_alarm(&rtc1, &rtc1ss);
|
||||
rtc_diff = get_rtc_diff(rtc0, rtc0ss, rtc1, rtc1ss);
|
||||
t0.val = t0.val + rtc_diff;
|
||||
force_time(t0);
|
||||
|
||||
/* Record time spent in deep sleep. */
|
||||
idle_dsleep_time_us += rtc_diff;
|
||||
|
||||
/* Calculate how close we were to missing deadline */
|
||||
margin_us = next_delay - rtc_diff;
|
||||
if (margin_us < 0)
|
||||
CPRINTS("overslept by %dus", -margin_us);
|
||||
|
||||
/* Record the closest to missing a deadline. */
|
||||
if (margin_us < dsleep_recovery_margin_us)
|
||||
dsleep_recovery_margin_us = margin_us;
|
||||
} else {
|
||||
idle_sleep_cnt++;
|
||||
|
||||
/* normal idle : only CPU clock stopped */
|
||||
asm("wfi");
|
||||
}
|
||||
asm volatile("cpsie i");
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_LOW_POWER_IDLE */
|
||||
|
||||
int clock_get_freq(void)
|
||||
{
|
||||
return CPU_CLOCK;
|
||||
}
|
||||
|
||||
void clock_enable_module(enum module_id module, int enable)
|
||||
{
|
||||
}
|
||||
|
||||
void clock_init(void)
|
||||
{
|
||||
/*
|
||||
* The initial state :
|
||||
* SYSCLK from HSI (=8MHz), no divider on AHB, APB1, APB2
|
||||
* PLL unlocked, RTC enabled on LSE
|
||||
*/
|
||||
|
||||
/* put 1 Wait-State for flash access to ensure proper reads at 48Mhz */
|
||||
STM32_FLASH_ACR = STM32_FLASH_ACR_LATENCY; /* 1 WS / Prefetch enabled */
|
||||
|
||||
config_hispeed_clock();
|
||||
|
||||
rtc_unlock_regs();
|
||||
|
||||
@@ -305,3 +427,27 @@ DECLARE_CONSOLE_COMMAND(rtc_alarm, command_rtc_alarm_test,
|
||||
NULL);
|
||||
#endif /* CONFIG_CMD_RTC_ALARM */
|
||||
|
||||
#ifdef CONFIG_LOW_POWER_IDLE
|
||||
/**
|
||||
* Print low power idle statistics
|
||||
*/
|
||||
static int command_idle_stats(int argc, char **argv)
|
||||
{
|
||||
timestamp_t ts = get_time();
|
||||
|
||||
ccprintf("Num idle calls that sleep: %d\n", idle_sleep_cnt);
|
||||
ccprintf("Num idle calls that deep-sleep: %d\n", idle_dsleep_cnt);
|
||||
ccprintf("Time spent in deep-sleep: %.6lds\n",
|
||||
idle_dsleep_time_us);
|
||||
ccprintf("Total time on: %.6lds\n", ts.val);
|
||||
ccprintf("Deep-sleep closest to wake deadline: %dus\n",
|
||||
dsleep_recovery_margin_us);
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
DECLARE_CONSOLE_COMMAND(idlestats, command_idle_stats,
|
||||
"",
|
||||
"Print last idle stats",
|
||||
NULL);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -153,6 +153,7 @@
|
||||
#ifdef CHIP_FAMILY_STM32F0
|
||||
#define STM32_USART_CR1(base) STM32_USART_REG(base, 0x00)
|
||||
#define STM32_USART_CR1_UE (1 << 0)
|
||||
#define STM32_USART_CR1_UESM (1 << 1)
|
||||
#define STM32_USART_CR1_RE (1 << 2)
|
||||
#define STM32_USART_CR1_TE (1 << 3)
|
||||
#define STM32_USART_CR1_RXNEIE (1 << 5)
|
||||
@@ -794,6 +795,7 @@ typedef volatile struct stm32_spi_regs stm32_spi_regs_t;
|
||||
#define STM32_FLASH_REGS_BASE 0x40022000
|
||||
|
||||
#define STM32_FLASH_ACR REG32(STM32_FLASH_REGS_BASE + 0x00)
|
||||
#define STM32_FLASH_ACR_LATENCY (1 << 0)
|
||||
#define STM32_FLASH_KEYR REG32(STM32_FLASH_REGS_BASE + 0x04)
|
||||
#define STM32_FLASH_OPTKEYR REG32(STM32_FLASH_REGS_BASE + 0x08)
|
||||
#define STM32_FLASH_SR REG32(STM32_FLASH_REGS_BASE + 0x0c)
|
||||
|
||||
Reference in New Issue
Block a user