• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 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 
15 #include "esp_system.h"
16 #include "esp32/rom/rtc.h"
17 #include "esp_private/system_internal.h"
18 #include "soc/rtc_periph.h"
19 
20 static void esp_reset_reason_clear_hint(void);
21 
22 static esp_reset_reason_t s_reset_reason;
23 
get_reset_reason(RESET_REASON rtc_reset_reason,esp_reset_reason_t reset_reason_hint)24 static esp_reset_reason_t get_reset_reason(RESET_REASON rtc_reset_reason, esp_reset_reason_t reset_reason_hint)
25 {
26     switch (rtc_reset_reason) {
27         case POWERON_RESET:
28             return ESP_RST_POWERON;
29 
30         /* For ESP32, ESP_RST_EXT is never returned */
31 
32 
33         case SW_CPU_RESET:
34         case SW_RESET:
35         case EXT_CPU_RESET: /* unused */
36             if (reset_reason_hint == ESP_RST_PANIC ||
37                 reset_reason_hint == ESP_RST_BROWNOUT ||
38                 reset_reason_hint == ESP_RST_TASK_WDT ||
39                 reset_reason_hint == ESP_RST_INT_WDT) {
40                 return reset_reason_hint;
41             }
42             return ESP_RST_SW;
43 
44         case DEEPSLEEP_RESET:
45             return ESP_RST_DEEPSLEEP;
46 
47         case TG0WDT_SYS_RESET:
48             return ESP_RST_TASK_WDT;
49 
50         case TG1WDT_SYS_RESET:
51             return ESP_RST_INT_WDT;
52 
53         case OWDT_RESET:
54         case RTCWDT_SYS_RESET:
55         case RTCWDT_RTC_RESET:
56         case RTCWDT_CPU_RESET:  /* unused */
57         case TGWDT_CPU_RESET:   /* unused */
58             return ESP_RST_WDT;
59 
60         case RTCWDT_BROWN_OUT_RESET:    /* unused */
61             return ESP_RST_BROWNOUT;
62 
63         case SDIO_RESET:
64             return ESP_RST_SDIO;
65 
66         case INTRUSION_RESET: /* unused */
67         default:
68             return ESP_RST_UNKNOWN;
69     }
70 }
71 
esp_reset_reason_init(void)72 static void __attribute__((constructor)) esp_reset_reason_init(void)
73 {
74     esp_reset_reason_t hint = esp_reset_reason_get_hint();
75     s_reset_reason = get_reset_reason(rtc_get_reset_reason(PRO_CPU_NUM),
76                                       hint);
77     if (hint != ESP_RST_UNKNOWN) {
78         esp_reset_reason_clear_hint();
79     }
80 }
81 
esp_reset_reason(void)82 esp_reset_reason_t esp_reset_reason(void)
83 {
84     return s_reset_reason;
85 }
86 
87 /* Reset reason hint is stored in RTC_RESET_CAUSE_REG, a.k.a. RTC_CNTL_STORE6_REG,
88  * a.k.a. RTC_ENTRY_ADDR_REG. It is safe to use this register both for the
89  * deep sleep wake stub entry address and for reset reason hint, since wake stub
90  * is only used for deep sleep reset, and in this case the reason provided by
91  * rtc_get_reset_reason is unambiguous.
92  *
93  * Same layout is used as for RTC_APB_FREQ_REG (a.k.a. RTC_CNTL_STORE5_REG):
94  * the value is replicated in low and high half-words. In addition to that,
95  * MSB is set to 1, which doesn't happen when RTC_CNTL_STORE6_REG contains
96  * deep sleep wake stub address.
97  */
98 
99 #define RST_REASON_BIT  0x80000000
100 #define RST_REASON_MASK 0x7FFF
101 #define RST_REASON_SHIFT 16
102 
103 /* in IRAM, can be called from panic handler */
esp_reset_reason_set_hint(esp_reset_reason_t hint)104 void IRAM_ATTR esp_reset_reason_set_hint(esp_reset_reason_t hint)
105 {
106     assert((hint & (~RST_REASON_MASK)) == 0);
107     uint32_t val = hint | (hint << RST_REASON_SHIFT) | RST_REASON_BIT;
108     REG_WRITE(RTC_RESET_CAUSE_REG, val);
109 }
110 
111 /* in IRAM, can be called from panic handler */
esp_reset_reason_get_hint(void)112 esp_reset_reason_t IRAM_ATTR esp_reset_reason_get_hint(void)
113 {
114     uint32_t reset_reason_hint = REG_READ(RTC_RESET_CAUSE_REG);
115     uint32_t high = (reset_reason_hint >> RST_REASON_SHIFT) & RST_REASON_MASK;
116     uint32_t low = reset_reason_hint & RST_REASON_MASK;
117     if ((reset_reason_hint & RST_REASON_BIT) == 0 || high != low) {
118         return ESP_RST_UNKNOWN;
119     }
120     return (esp_reset_reason_t) low;
121 }
esp_reset_reason_clear_hint(void)122 static void esp_reset_reason_clear_hint(void)
123 {
124     REG_WRITE(RTC_RESET_CAUSE_REG, 0);
125 }
126