Skip to content

Commit 773715d

Browse files
committed
Merge branch 'feature/support_refresh_brownout_v1' into 'master'
spi_flash: send reset when brownout detected on XMC flash Closes IDF-3882 See merge request espressif/esp-idf!16873
2 parents e94435d + 6a2d350 commit 773715d

File tree

36 files changed

+360
-148
lines changed

36 files changed

+360
-148
lines changed

components/bootloader_support/bootloader_flash/include/bootloader_flash.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ esp_err_t bootloader_flash_xmc_startup(void);
4949
*/
5050
esp_err_t __attribute__((weak)) bootloader_flash_unlock(void);
5151

52+
/**
53+
* @brief Reset the flash chip (66H + 99H).
54+
*
55+
* @return ESP_OK if success, otherwise ESP_FAIL.
56+
*/
57+
esp_err_t bootloader_flash_reset_chip(void);
5258

5359
#ifdef __cplusplus
5460
}

components/bootloader_support/bootloader_flash/src/bootloader_flash.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -730,3 +730,44 @@ esp_err_t IRAM_ATTR bootloader_flash_xmc_startup(void)
730730
}
731731

732732
#endif //XMC_SUPPORT
733+
734+
FORCE_INLINE_ATTR void bootloader_mspi_reset(void)
735+
{
736+
#if CONFIG_IDF_TARGET_ESP32
737+
SPI1.slave.sync_reset = 0;
738+
SPI0.slave.sync_reset = 0;
739+
SPI1.slave.sync_reset = 1;
740+
SPI0.slave.sync_reset = 1;
741+
SPI1.slave.sync_reset = 0;
742+
SPI0.slave.sync_reset = 0;
743+
#else
744+
SPIMEM1.ctrl2.sync_reset = 0;
745+
SPIMEM0.ctrl2.sync_reset = 0;
746+
SPIMEM1.ctrl2.sync_reset = 1;
747+
SPIMEM0.ctrl2.sync_reset = 1;
748+
SPIMEM1.ctrl2.sync_reset = 0;
749+
SPIMEM0.ctrl2.sync_reset = 0;
750+
#endif
751+
}
752+
753+
esp_err_t IRAM_ATTR bootloader_flash_reset_chip(void)
754+
{
755+
bootloader_mspi_reset();
756+
// Seems that sync_reset cannot make host totally idle.'
757+
// Sending an extra(useless) command to make the host idle in order to send reset command.
758+
bootloader_execute_flash_command(0x05, 0, 0, 0);
759+
#if CONFIG_IDF_TARGET_ESP32
760+
if (SPI1.ext2.st != 0)
761+
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
762+
if (SPIMEM1.fsm.st != 0)
763+
#else
764+
if (SPIMEM1.fsm.spi0_mst_st != 0)
765+
#endif
766+
{
767+
return ESP_FAIL;
768+
}
769+
bootloader_execute_flash_command(0x66, 0, 0, 0);
770+
bootloader_execute_flash_command(0x99, 0, 0, 0);
771+
772+
return ESP_OK;
773+
}

components/driver/esp32/touch_sensor.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,13 @@ static esp_err_t _touch_pad_read(touch_pad_t touch_num, uint16_t *touch_value, t
7070
esp_err_t touch_pad_isr_handler_register(void (*fn)(void *), void *arg, int no_use, intr_handle_t *handle_no_use)
7171
{
7272
ESP_RETURN_ON_FALSE(fn, ESP_ERR_INVALID_ARG, TOUCH_TAG, "Touch_Pad ISR null");
73-
return rtc_isr_register(fn, arg, RTC_CNTL_TOUCH_INT_ST_M);
73+
return rtc_isr_register(fn, arg, RTC_CNTL_TOUCH_INT_ST_M, 0);
7474
}
7575

7676
esp_err_t touch_pad_isr_register(intr_handler_t fn, void *arg)
7777
{
7878
ESP_RETURN_ON_FALSE(fn, ESP_ERR_INVALID_ARG, TOUCH_TAG, "Touch_Pad ISR null");
79-
return rtc_isr_register(fn, arg, RTC_CNTL_TOUCH_INT_ST_M);
79+
return rtc_isr_register(fn, arg, RTC_CNTL_TOUCH_INT_ST_M, 0);
8080
}
8181

8282
static uint32_t _touch_filter_iir(uint32_t in_now, uint32_t out_last, uint32_t k)

components/driver/esp32s2/touch_sensor.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,10 +106,10 @@ esp_err_t touch_pad_isr_register(intr_handler_t fn, void *arg, touch_pad_intr_ma
106106
en_msk |= RTC_CNTL_TOUCH_APPROACH_LOOP_DONE_INT_ST_M;
107107
}
108108
#endif
109-
esp_err_t ret = rtc_isr_register(fn, arg, en_msk);
109+
esp_err_t ret = rtc_isr_register(fn, arg, en_msk, 0);
110110
/* Must ensure: After being registered, it is executed first. */
111111
if ( (ret == ESP_OK) && (reg_flag == false) && (intr_mask & (TOUCH_PAD_INTR_MASK_SCAN_DONE | TOUCH_PAD_INTR_MASK_TIMEOUT)) ) {
112-
rtc_isr_register(touch_pad_workaround_isr_internal, NULL, RTC_CNTL_TOUCH_SCAN_DONE_INT_ST_M | RTC_CNTL_TOUCH_TIMEOUT_INT_ST_M);
112+
rtc_isr_register(touch_pad_workaround_isr_internal, NULL, RTC_CNTL_TOUCH_SCAN_DONE_INT_ST_M | RTC_CNTL_TOUCH_TIMEOUT_INT_ST_M, 0);
113113
reg_flag = true;
114114
}
115115

components/driver/esp32s3/touch_sensor.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ esp_err_t touch_pad_isr_register(intr_handler_t fn, void *arg, touch_pad_intr_ma
8585
en_msk |= RTC_CNTL_TOUCH_APPROACH_LOOP_DONE_INT_ST_M;
8686
}
8787
#endif
88-
esp_err_t ret = rtc_isr_register(fn, arg, en_msk);
88+
esp_err_t ret = rtc_isr_register(fn, arg, en_msk, 0);
8989

9090
return ret;
9191
}

components/esp_hw_support/include/esp_private/rtc_ctrl.h

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
extern "C" {
1515
#endif
1616

17+
#define RTC_INTR_FLAG_IRAM (BIT(0)) /*< Some rtc interrupts can be called with cache disabled */
18+
1719
/**
1820
* @brief Register a handler for specific RTC_CNTL interrupts
1921
*
@@ -25,13 +27,17 @@ extern "C" {
2527
* @param handler_arg argument to be passed to the handler
2628
* @param rtc_intr_mask combination of RTC_CNTL_*_INT_ENA bits indicating the
2729
* sources to call the handler for
30+
* @param flags An ORred mask of the RTC_INTR_FLAG_* defines. You can pass different
31+
* flags to it to realize different purpose. If 0, the interrupt will
32+
* not handle anything special. If you pass `RTC_INTR_FLAG_IRAM`, means
33+
* the interrupt can be triggered with cache disabled.
2834
* @return
2935
* - ESP_OK on success
3036
* - ESP_ERR_NO_MEM not enough memory to allocate handler structure
3137
* - other errors returned by esp_intr_alloc
3238
*/
3339
esp_err_t rtc_isr_register(intr_handler_t handler, void* handler_arg,
34-
uint32_t rtc_intr_mask);
40+
uint32_t rtc_intr_mask, uint32_t flags);
3541
/**
3642
* @brief Deregister the handler previously registered using rtc_isr_register
3743
* @param handler handler function to call (as passed to rtc_isr_register)
@@ -43,6 +49,24 @@ esp_err_t rtc_isr_register(intr_handler_t handler, void* handler_arg,
4349
*/
4450
esp_err_t rtc_isr_deregister(intr_handler_t handler, void* handler_arg);
4551

52+
/**
53+
* @brief Disable the RTC interrupt that is allowed to be executed when cache is disabled.
54+
* cache disabled. Internal interrupt handle function will call this function in interrupt
55+
* handler function. Disable bits when `esp_intr_noniram_disable` is called.
56+
*
57+
* @param cpu CPU number.
58+
*/
59+
void rtc_isr_noniram_disable(uint32_t cpu);
60+
61+
/**
62+
* @brief Enable the RTC interrupt that is allowed to be executed when cache is disabled.
63+
* cache disabled. Internal interrupt handle function will call this function in interrupt
64+
* handler function. Enable bits when `esp_intr_noniram_enable` is called.
65+
*
66+
* @param cpu CPU number.
67+
*/
68+
void rtc_isr_noniram_enable(uint32_t cpu);
69+
4670
#ifdef __cplusplus
4771
}
4872
#endif

components/esp_hw_support/intr_alloc.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "esp_intr_alloc.h"
2121
#include "esp_attr.h"
2222
#include "hal/cpu_hal.h"
23+
#include "esp_private/rtc_ctrl.h"
2324
#include "hal/interrupt_controller_hal.h"
2425

2526
#if !CONFIG_FREERTOS_UNICORE
@@ -797,6 +798,8 @@ void IRAM_ATTR esp_intr_noniram_disable(void)
797798
non_iram_int_disabled_flag[cpu] = true;
798799
oldint = interrupt_controller_hal_read_interrupt_mask();
799800
interrupt_controller_hal_disable_interrupts(non_iram_ints);
801+
// Disable the RTC bit which don't want to be put in IRAM.
802+
rtc_isr_noniram_disable(cpu);
800803
// Save disabled ints
801804
non_iram_int_disabled[cpu] = oldint & non_iram_ints;
802805
portEXIT_CRITICAL_SAFE(&spinlock);
@@ -812,6 +815,7 @@ void IRAM_ATTR esp_intr_noniram_enable(void)
812815
}
813816
non_iram_int_disabled_flag[cpu] = false;
814817
interrupt_controller_hal_enable_interrupts(non_iram_ints);
818+
rtc_isr_noniram_enable(cpu);
815819
portEXIT_CRITICAL_SAFE(&spinlock);
816820
}
817821

components/esp_hw_support/port/esp32/Kconfig.hw_support

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ choice ESP32_REV_MIN
77

88
config ESP32_REV_MIN_0
99
bool "Rev 0"
10+
# Brownout on Rev 0 is bugged, must use interrupt
11+
select ESP_SYSTEM_BROWNOUT_INTR
1012
config ESP32_REV_MIN_1
1113
bool "Rev 1"
1214
config ESP32_REV_MIN_2

components/esp_hw_support/rtc_module.c

Lines changed: 60 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,23 @@
1919
#include "esp_intr_alloc.h"
2020
#include "sys/lock.h"
2121
#include "esp_private/rtc_ctrl.h"
22+
#include "esp_attr.h"
2223

2324
#ifndef NDEBUG
2425
// Enable built-in checks in queue.h in debug builds
2526
#define INVARIANTS
2627
#endif
2728
#include "sys/queue.h"
2829

30+
#define NOT_REGISTERED (-1)
31+
2932
portMUX_TYPE rtc_spinlock = portMUX_INITIALIZER_UNLOCKED;
33+
// Disable the interrupt which cannot work without cache.
34+
static DRAM_ATTR uint32_t rtc_intr_cache;
35+
static DRAM_ATTR uint32_t rtc_intr_enabled;
36+
static DRAM_ATTR int rtc_isr_cpu = NOT_REGISTERED; // Unused number
37+
static void s_rtc_isr_noniram_hook(uint32_t rtc_intr_mask);
38+
static void s_rtc_isr_noniram_hook_relieve(uint32_t rtc_intr_mask);
3039

3140
/*---------------------------------------------------------------
3241
INTERRUPT HANDLER
@@ -37,15 +46,16 @@ typedef struct rtc_isr_handler_ {
3746
uint32_t mask;
3847
intr_handler_t handler;
3948
void* handler_arg;
49+
uint32_t flags;
4050
SLIST_ENTRY(rtc_isr_handler_) next;
4151
} rtc_isr_handler_t;
4252

43-
static SLIST_HEAD(rtc_isr_handler_list_, rtc_isr_handler_) s_rtc_isr_handler_list =
53+
static DRAM_ATTR SLIST_HEAD(rtc_isr_handler_list_, rtc_isr_handler_) s_rtc_isr_handler_list =
4454
SLIST_HEAD_INITIALIZER(s_rtc_isr_handler_list);
45-
portMUX_TYPE s_rtc_isr_handler_list_lock = portMUX_INITIALIZER_UNLOCKED;
55+
static DRAM_ATTR portMUX_TYPE s_rtc_isr_handler_list_lock = portMUX_INITIALIZER_UNLOCKED;
4656
static intr_handle_t s_rtc_isr_handle;
4757

48-
static void rtc_isr(void* arg)
58+
IRAM_ATTR static void rtc_isr(void* arg)
4959
{
5060
uint32_t status = REG_READ(RTC_CNTL_INT_ST_REG);
5161
rtc_isr_handler_t* it;
@@ -71,32 +81,37 @@ static esp_err_t rtc_isr_ensure_installed(void)
7181

7282
REG_WRITE(RTC_CNTL_INT_ENA_REG, 0);
7383
REG_WRITE(RTC_CNTL_INT_CLR_REG, UINT32_MAX);
74-
err = esp_intr_alloc(ETS_RTC_CORE_INTR_SOURCE, 0, &rtc_isr, NULL, &s_rtc_isr_handle);
84+
err = esp_intr_alloc(ETS_RTC_CORE_INTR_SOURCE, ESP_INTR_FLAG_IRAM, &rtc_isr, NULL, &s_rtc_isr_handle);
7585
if (err != ESP_OK) {
7686
goto out;
7787
}
78-
88+
rtc_isr_cpu = esp_intr_get_cpu(s_rtc_isr_handle);
7989
out:
8090
portEXIT_CRITICAL(&s_rtc_isr_handler_list_lock);
8191
return err;
8292
}
8393

84-
85-
esp_err_t rtc_isr_register(intr_handler_t handler, void* handler_arg, uint32_t rtc_intr_mask)
94+
esp_err_t rtc_isr_register(intr_handler_t handler, void* handler_arg, uint32_t rtc_intr_mask, uint32_t flags)
8695
{
8796
esp_err_t err = rtc_isr_ensure_installed();
8897
if (err != ESP_OK) {
8998
return err;
9099
}
91100

92-
rtc_isr_handler_t* item = malloc(sizeof(*item));
101+
rtc_isr_handler_t* item = heap_caps_malloc(sizeof(*item), MALLOC_CAP_INTERNAL);
93102
if (item == NULL) {
94103
return ESP_ERR_NO_MEM;
95104
}
96105
item->handler = handler;
97106
item->handler_arg = handler_arg;
98107
item->mask = rtc_intr_mask;
108+
item->flags = flags;
99109
portENTER_CRITICAL(&s_rtc_isr_handler_list_lock);
110+
if (flags & RTC_INTR_FLAG_IRAM) {
111+
s_rtc_isr_noniram_hook(rtc_intr_mask);
112+
} else {
113+
s_rtc_isr_noniram_hook_relieve(rtc_intr_mask);
114+
}
100115
SLIST_INSERT_HEAD(&s_rtc_isr_handler_list, item, next);
101116
portEXIT_CRITICAL(&s_rtc_isr_handler_list_lock);
102117
return ESP_OK;
@@ -116,6 +131,9 @@ esp_err_t rtc_isr_deregister(intr_handler_t handler, void* handler_arg)
116131
SLIST_REMOVE_AFTER(prev, next);
117132
}
118133
found = true;
134+
if (it->flags & RTC_INTR_FLAG_IRAM) {
135+
s_rtc_isr_noniram_hook_relieve(it->mask);
136+
}
119137
free(it);
120138
break;
121139
}
@@ -124,3 +142,37 @@ esp_err_t rtc_isr_deregister(intr_handler_t handler, void* handler_arg)
124142
portEXIT_CRITICAL(&s_rtc_isr_handler_list_lock);
125143
return found ? ESP_OK : ESP_ERR_INVALID_STATE;
126144
}
145+
146+
/**
147+
* @brief This helper function can be used to avoid the interrupt to be triggered with cache disabled.
148+
* There are lots of different signals on RTC module (i.e. sleep_wakeup, wdt, brownout_detect, etc.)
149+
* We might want some of them can be triggered with cache disabled, some are not. Therefore, this function
150+
* is created to avoid those which do not want to be triggered with cache disabled.
151+
*
152+
* @param rtc_intr_mask the mask of the rtc interrupt.
153+
*/
154+
static void s_rtc_isr_noniram_hook(uint32_t rtc_intr_mask)
155+
{
156+
rtc_intr_cache |= rtc_intr_mask;
157+
}
158+
159+
static void s_rtc_isr_noniram_hook_relieve(uint32_t rtc_intr_mask)
160+
{
161+
rtc_intr_cache &= ~rtc_intr_mask;
162+
}
163+
164+
IRAM_ATTR void rtc_isr_noniram_disable(uint32_t cpu)
165+
{
166+
if (rtc_isr_cpu == cpu) {
167+
rtc_intr_enabled |= RTCCNTL.int_ena.val;
168+
RTCCNTL.int_ena.val &= rtc_intr_cache;
169+
}
170+
}
171+
172+
IRAM_ATTR void rtc_isr_noniram_enable(uint32_t cpu)
173+
{
174+
if (rtc_isr_cpu == cpu) {
175+
RTCCNTL.int_ena.val = rtc_intr_enabled;
176+
rtc_intr_enabled = 0;
177+
}
178+
}

components/esp_system/Kconfig

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,18 @@ menu "ESP System Settings"
533533
# Insert chip-specific system config
534534
rsource "./port/soc/$IDF_TARGET/Kconfig.system"
535535

536+
config ESP_SYSTEM_BROWNOUT_INTR
537+
bool
538+
default n
539+
help
540+
This config allows to trigger an interrupt when brownout detected. Software restart will be done
541+
at the end of the default callback.
542+
Two occasions need to restart the chip with interrupt so far.
543+
(1). For ESP32 version 1, brown-out reset function doesn't work (see ESP32 errata 3.4).
544+
So that we must restart from interrupt.
545+
(2). For special workflow, the chip needs do more things instead of restarting directly. This part
546+
needs to be done in callback function of interrupt.
547+
536548
endmenu # ESP System Settings
537549

538550
menu "IPC (Inter-Processor Call)"

0 commit comments

Comments
 (0)