summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Chen <philipchen@google.com>2017-09-22 14:29:40 -0700
committerchrome-bot <chrome-bot@chromium.org>2017-10-11 13:19:33 -0700
commit982f2bbfab02400cb09b7d7102db3285c1723762 (patch)
tree1d7e9b38c83b7a54710c61028df3dcaf70a5791d
parentdf12bc1c0246ceec39f28151efadb73f8e5fd7a5 (diff)
downloadchrome-ec-982f2bbfab02400cb09b7d7102db3285c1723762.tar.gz
chip/stm32/clock: Optionally use LSE as RTCCLK
The default RTCCLK comes from LSI, which can vary from 30kHz to 60kHz. To use stm32 RTC for applications requiring accurate timing, let's setup LSE (a more accurate clock source) as RTCCLK. Also fix a typo in register.h as 'BCDR' should be 'BDCR' globally. BUG=b:63908519 BRANCH=none TEST=boot scarlet rev1 and wait for an hour, confirm rtc time == kernel system time. Change-Id: If4728bdd3b6384316e5337004a49c172eaec869d Signed-off-by: Philip Chen <philipchen@google.com> Reviewed-on: https://chromium-review.googlesource.com/679601 Commit-Ready: Philip Chen <philipchen@chromium.org> Tested-by: Philip Chen <philipchen@chromium.org> Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r--chip/stm32/clock-stm32f0.c26
-rw-r--r--chip/stm32/clock-stm32f4.c4
-rw-r--r--chip/stm32/registers.h16
-rw-r--r--chip/stm32/system.c32
-rw-r--r--include/config.h3
5 files changed, 55 insertions, 26 deletions
diff --git a/chip/stm32/clock-stm32f0.c b/chip/stm32/clock-stm32f0.c
index b7eb68ca07..fe1ccd4aa4 100644
--- a/chip/stm32/clock-stm32f0.c
+++ b/chip/stm32/clock-stm32f0.c
@@ -59,26 +59,27 @@ static int dsleep_recovery_margin_us = 1000000;
#endif /* CONFIG_LOW_POWER_IDLE */
/*
- * RTC clock frequency (connected to LSI clock)
+ * RTC clock frequency (By default connected to LSI clock)
*
- * TODO(crosbug.com/p/12281): Calibrate LSI frequency on a per-chip basis. The
- * LSI on any given chip can be between 30 kHz to 60 kHz. Without calibration,
- * LSI frequency may be off by as much as 50%. Fortunately, we don't do any
- * high-precision delays based solely on LSI.
- */
-/*
- * Set synchronous clock freq to LSI/2 (20kHz) to maximize subsecond
- * resolution. Set asynchronous clock to 1 Hz.
+ * The LSI on any given chip can be between 30 kHz to 60 kHz.
+ * Without calibration, LSI frequency may be off by as much as 50%.
+ *
+ * Set synchronous clock freq to (RTC clock source / 2) to maximize
+ * subsecond resolution. Set asynchronous clock to 1 Hz.
*/
-#define RTC_FREQ (40000 / 2) /* Hz */
+
+#ifdef CONFIG_STM32_CLOCK_LSE
+#define RTC_FREQ (32768 / (RTC_PREDIV_A + 1)) /* Hz */
+#else /* LSI clock, 40kHz-ish */
+#define RTC_FREQ (40000 / (RTC_PREDIV_A + 1)) /* Hz */
+#endif
#define RTC_PREDIV_S (RTC_FREQ - 1)
#define RTC_PREDIV_A 1
#define US_PER_RTC_TICK (1000000 / RTC_FREQ)
-
int32_t rtcss_to_us(uint32_t rtcss)
{
- return ((RTC_PREDIV_S - rtcss) * US_PER_RTC_TICK);
+ return ((RTC_PREDIV_S - (rtcss & 0x7fff)) * US_PER_RTC_TICK);
}
uint32_t us_to_rtcss(int32_t us)
@@ -86,7 +87,6 @@ uint32_t us_to_rtcss(int32_t us)
return (RTC_PREDIV_S - (us / US_PER_RTC_TICK));
}
-
void config_hispeed_clock(void)
{
#ifdef CHIP_FAMILY_STM32F3
diff --git a/chip/stm32/clock-stm32f4.c b/chip/stm32/clock-stm32f4.c
index eacb3d59e0..ed4ffe6848 100644
--- a/chip/stm32/clock-stm32f4.c
+++ b/chip/stm32/clock-stm32f4.c
@@ -166,13 +166,13 @@ void config_hispeed_clock(void)
/* Setup RTC Clock input */
STM32_RCC_BDCR |= STM32_RCC_BDCR_BDRST;
#ifdef CONFIG_STM32_CLOCK_HSE_HZ
- STM32_RCC_BDCR = STM32_RCC_BDCR_RTCEN | BCDR_RTCSEL(BDCR_SRC_HSE);
+ STM32_RCC_BDCR = STM32_RCC_BDCR_RTCEN | BDCR_RTCSEL(BDCR_SRC_HSE);
#else
/* Ensure that LSI is ON */
wait_for_ready(&(STM32_RCC_CSR),
STM32_RCC_CSR_LSION, STM32_RCC_CSR_LSIRDY);
- STM32_RCC_BDCR = STM32_RCC_BDCR_RTCEN | BCDR_RTCSEL(BDCR_SRC_LSI);
+ STM32_RCC_BDCR = STM32_RCC_BDCR_RTCEN | BDCR_RTCSEL(BDCR_SRC_LSI);
#endif
}
diff --git a/chip/stm32/registers.h b/chip/stm32/registers.h
index bfe5b7321c..491718f631 100644
--- a/chip/stm32/registers.h
+++ b/chip/stm32/registers.h
@@ -1109,11 +1109,6 @@ typedef volatile struct timer_ctlr timer_ctlr_t;
#define STM32_RCC_APB2LPENR REG32(STM32_RCC_BASE + 0x64)
#define STM32_RCC_BDCR REG32(STM32_RCC_BASE + 0x70)
-#define STM32_RCC_BDCR_BDRST (1 << 16)
-#define STM32_RCC_BDCR_RTCEN (1 << 15)
-#define BCDR_RTCSEL(source) (((source) & 0x3) << 8)
-#define BDCR_SRC_HSE 0x3
-#define BDCR_SRC_LSI 0x2
#define STM32_RCC_CSR REG32(STM32_RCC_BASE + 0x74)
#define STM32_RCC_CSR_LSION (1 << 0)
#define STM32_RCC_CSR_LSIRDY (1 << 1)
@@ -1141,6 +1136,17 @@ typedef volatile struct timer_ctlr timer_ctlr_t;
#error Unsupported chip variant
#endif
+/* RTC domain control register */
+#define STM32_RCC_BDCR_BDRST (1 << 16)
+#define STM32_RCC_BDCR_RTCEN (1 << 15)
+#define STM32_RCC_BDCR_LSERDY (1 << 1)
+#define STM32_RCC_BDCR_LSEON (1 << 0)
+#define BDCR_RTCSEL_MASK ((0x3) << 8)
+#define BDCR_RTCSEL(source) (((source) << 8) & BDCR_RTCSEL_MASK)
+#define BDCR_SRC_LSE 0x1
+#define BDCR_SRC_LSI 0x2
+#define BDCR_SRC_HSE 0x3
+
/* Peripheral bits for RCC_APB/AHB and DBGMCU regs */
#define STM32_RCC_PB1_TIM2 (1 << 0)
#define STM32_RCC_PB1_TIM3 (1 << 1)
diff --git a/chip/stm32/system.c b/chip/stm32/system.c
index d0c69101ef..884a5d9ed2 100644
--- a/chip/stm32/system.c
+++ b/chip/stm32/system.c
@@ -18,6 +18,18 @@
#include "version.h"
#include "watchdog.h"
+#ifdef CONFIG_STM32_CLOCK_LSE
+#define BDCR_SRC BDCR_SRC_LSE
+#define BDCR_RDY STM32_RCC_BDCR_LSERDY
+#else
+#define BDCR_SRC BDCR_SRC_LSI
+#define BDCR_RDY 0
+#endif
+#define BDCR_ENABLE_VALUE (STM32_RCC_BDCR_RTCEN | BDCR_RTCSEL(BDCR_SRC) | \
+ BDCR_RDY)
+#define BDCR_ENABLE_MASK (BDCR_ENABLE_VALUE | BDCR_RTCSEL_MASK | \
+ STM32_RCC_BDCR_BDRST)
+
enum bkpdata_index {
BKPDATA_INDEX_SCRATCHPAD, /* General-purpose scratchpad */
BKPDATA_INDEX_SAVED_RESET_FLAGS, /* Saved reset flags */
@@ -249,18 +261,26 @@ void system_pre_init(void)
/* re-configure RTC if needed */
#ifdef CHIP_FAMILY_STM32L
if ((STM32_RCC_CSR & 0x00C30000) != 0x00420000) {
- /* the RTC settings are bad, we need to reset it */
+ /* The RTC settings are bad, we need to reset it */
STM32_RCC_CSR |= 0x00800000;
/* Enable RTC and use LSI as clock source */
STM32_RCC_CSR = (STM32_RCC_CSR & ~0x00C30000) | 0x00420000;
}
#elif defined(CHIP_FAMILY_STM32F0) || defined(CHIP_FAMILY_STM32F3) || \
defined(CHIP_FAMILY_STM32L4) || defined(CHIP_FAMILY_STM32F4)
- if ((STM32_RCC_BDCR & 0x00018300) != 0x00008200) {
- /* the RTC settings are bad, we need to reset it */
- STM32_RCC_BDCR |= 0x00010000;
- /* Enable RTC and use LSI as clock source */
- STM32_RCC_BDCR = (STM32_RCC_BDCR & ~0x00018300) | 0x00008200;
+ if ((STM32_RCC_BDCR & BDCR_ENABLE_MASK) != BDCR_ENABLE_VALUE) {
+ /* The RTC settings are bad, we need to reset it */
+ STM32_RCC_BDCR |= STM32_RCC_BDCR_BDRST;
+ STM32_RCC_BDCR = STM32_RCC_BDCR & ~BDCR_ENABLE_MASK;
+#ifdef CONFIG_STM32_CLOCK_LSE
+ /* Turn on LSE */
+ STM32_RCC_BDCR |= STM32_RCC_BDCR_LSEON;
+ /* Wait for LSE to be ready */
+ while (!(STM32_RCC_BDCR & STM32_RCC_BDCR_LSERDY))
+ ;
+#endif
+ /* Select clock source and enable RTC */
+ STM32_RCC_BDCR |= BDCR_RTCSEL(BDCR_SRC) | STM32_RCC_BDCR_RTCEN;
}
#else
#error "Unsupported chip family"
diff --git a/include/config.h b/include/config.h
index 86dacbe74f..f60766d165 100644
--- a/include/config.h
+++ b/include/config.h
@@ -668,6 +668,9 @@
/* Indicate if a clock source is connected to stm32f4's "HSE" specific input */
#undef CONFIG_STM32_CLOCK_HSE_HZ
+/* Indicate if a clock source is connected to "LSE" specific input */
+#undef CONFIG_STM32_CLOCK_LSE
+
/*
* Chip config for clock source
* define = external crystal oscillator / undef = internal clock source