1 // Copyright 2020 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 #include <stdint.h>
15 #include <time.h>
16 #include <sys/time.h>
17 #include <sys/lock.h>
18 
19 #include "esp_attr.h"
20 #include "esp_system.h"
21 
22 #include "soc/rtc.h"
23 #include "esp_rom_sys.h"
24 
25 #include "esp_private/system_internal.h"
26 
27 #include "esp_time_impl.h"
28 
29 #include "sdkconfig.h"
30 
31 #if CONFIG_IDF_TARGET_ESP32
32 #include "esp32/rom/rtc.h"
33 #include "esp32/clk.h"
34 #include "esp32/rtc.h"
35 #elif CONFIG_IDF_TARGET_ESP32S2
36 #include "esp32s2/rom/rtc.h"
37 #include "esp32s2/clk.h"
38 #include "esp32s2/rtc.h"
39 #elif CONFIG_IDF_TARGET_ESP32S3
40 #include "esp32s3/rom/rtc.h"
41 #include "esp32s3/clk.h"
42 #include "esp32s3/rtc.h"
43 #elif CONFIG_IDF_TARGET_ESP32C3
44 #include "esp32c3/rom/rtc.h"
45 #include "esp32c3/clk.h"
46 #include "esp32c3/rtc.h"
47 #elif CONFIG_IDF_TARGET_ESP32H2
48 #include "esp32h2/rom/rtc.h"
49 #include "esp32h2/clk.h"
50 #include "esp32h2/rtc.h"
51 #endif
52 
53 
54 
55 // Offset between FRC timer and the RTC.
56 // Initialized after reset or light sleep.
57 #if defined(CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER) && defined(CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER)
58 int64_t s_microseconds_offset = 0;
59 #endif
60 
61 #ifndef CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER
62 static uint64_t s_boot_time; // when RTC is used to persist time, two RTC_STORE registers are used to store boot time instead
63 #endif
64 
65 static _lock_t s_boot_time_lock;
66 
67 #if defined( CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER ) || defined( CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER )
esp_time_impl_get_time_since_boot(void)68 uint64_t esp_time_impl_get_time_since_boot(void)
69 {
70     uint64_t microseconds = 0;
71 
72 #ifdef CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER
73 #ifdef CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER
74     microseconds = s_microseconds_offset + esp_system_get_time();
75 #else
76     microseconds = esp_system_get_time();
77 #endif // CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER
78 #elif defined(CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER)
79     microseconds = esp_rtc_get_time_us();
80 #endif // CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER
81     return microseconds;
82 }
83 
esp_time_impl_get_time(void)84 uint64_t esp_time_impl_get_time(void)
85 {
86     uint64_t microseconds = 0;
87 #if defined( CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER )
88     microseconds = esp_system_get_time();
89 #elif defined( CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER )
90     microseconds = esp_rtc_get_time_us();
91 #endif // CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER
92     return microseconds;
93 }
94 
95 #endif // defined( CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER ) || defined( CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER )
96 
97 
esp_time_impl_set_boot_time(uint64_t time_us)98 void esp_time_impl_set_boot_time(uint64_t time_us)
99 {
100     _lock_acquire(&s_boot_time_lock);
101 #ifdef CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER
102     REG_WRITE(RTC_BOOT_TIME_LOW_REG, (uint32_t) (time_us & 0xffffffff));
103     REG_WRITE(RTC_BOOT_TIME_HIGH_REG, (uint32_t) (time_us >> 32));
104 #else
105     s_boot_time = time_us;
106 #endif
107     _lock_release(&s_boot_time_lock);
108 }
109 
esp_time_impl_get_boot_time(void)110 uint64_t esp_time_impl_get_boot_time(void)
111 {
112     uint64_t result;
113     _lock_acquire(&s_boot_time_lock);
114 #ifdef CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER
115     result = ((uint64_t) REG_READ(RTC_BOOT_TIME_LOW_REG)) + (((uint64_t) REG_READ(RTC_BOOT_TIME_HIGH_REG)) << 32);
116 #else
117     result = s_boot_time;
118 #endif
119     _lock_release(&s_boot_time_lock);
120     return result;
121 }
122 
esp_set_time_from_rtc(void)123 void esp_set_time_from_rtc(void)
124 {
125 #if defined( CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER ) && defined( CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER )
126     // initialize time from RTC clock
127     s_microseconds_offset = esp_rtc_get_time_us() - esp_system_get_time();
128 #endif // CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER && CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER
129 }
130 
esp_sync_counters_rtc_and_frc(void)131 void esp_sync_counters_rtc_and_frc(void)
132 {
133 #if defined( CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER ) && defined( CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER )
134     struct timeval tv;
135     gettimeofday(&tv, NULL);
136     settimeofday(&tv, NULL);
137     int64_t s_microseconds_offset_cur = esp_rtc_get_time_us() - esp_system_get_time();
138     esp_time_impl_set_boot_time(esp_time_impl_get_boot_time() + ((int64_t)s_microseconds_offset - s_microseconds_offset_cur));
139 #endif
140 }
141 
esp_time_impl_init(void)142 void esp_time_impl_init(void)
143 {
144     esp_set_time_from_rtc();
145 }
146