Skip to content

Commit

Permalink
spi_flash: Making XMC flash works more stable when brownout detected
Browse files Browse the repository at this point in the history
  • Loading branch information
mythbuster5 committed Jun 2, 2022
1 parent 890f046 commit 6a2d350
Show file tree
Hide file tree
Showing 27 changed files with 259 additions and 132 deletions.
Expand Up @@ -49,6 +49,12 @@ esp_err_t bootloader_flash_xmc_startup(void);
*/
esp_err_t __attribute__((weak)) bootloader_flash_unlock(void);

/**
* @brief Reset the flash chip (66H + 99H).
*
* @return ESP_OK if success, otherwise ESP_FAIL.
*/
esp_err_t bootloader_flash_reset_chip(void);

#ifdef __cplusplus
}
Expand Down
Expand Up @@ -730,3 +730,44 @@ esp_err_t IRAM_ATTR bootloader_flash_xmc_startup(void)
}

#endif //XMC_SUPPORT

FORCE_INLINE_ATTR void bootloader_mspi_reset(void)
{
#if CONFIG_IDF_TARGET_ESP32
SPI1.slave.sync_reset = 0;
SPI0.slave.sync_reset = 0;
SPI1.slave.sync_reset = 1;
SPI0.slave.sync_reset = 1;
SPI1.slave.sync_reset = 0;
SPI0.slave.sync_reset = 0;
#else
SPIMEM1.ctrl2.sync_reset = 0;
SPIMEM0.ctrl2.sync_reset = 0;
SPIMEM1.ctrl2.sync_reset = 1;
SPIMEM0.ctrl2.sync_reset = 1;
SPIMEM1.ctrl2.sync_reset = 0;
SPIMEM0.ctrl2.sync_reset = 0;
#endif
}

esp_err_t IRAM_ATTR bootloader_flash_reset_chip(void)
{
bootloader_mspi_reset();
// Seems that sync_reset cannot make host totally idle.'
// Sending an extra(useless) command to make the host idle in order to send reset command.
bootloader_execute_flash_command(0x05, 0, 0, 0);
#if CONFIG_IDF_TARGET_ESP32
if (SPI1.ext2.st != 0)
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
if (SPIMEM1.fsm.st != 0)
#else
if (SPIMEM1.fsm.spi0_mst_st != 0)
#endif
{
return ESP_FAIL;
}
bootloader_execute_flash_command(0x66, 0, 0, 0);
bootloader_execute_flash_command(0x99, 0, 0, 0);

return ESP_OK;
}
2 changes: 2 additions & 0 deletions components/esp_hw_support/port/esp32/Kconfig.hw_support
Expand Up @@ -7,6 +7,8 @@ choice ESP32_REV_MIN

config ESP32_REV_MIN_0
bool "Rev 0"
# Brownout on Rev 0 is bugged, must use interrupt
select ESP_SYSTEM_BROWNOUT_INTR
config ESP32_REV_MIN_1
bool "Rev 1"
config ESP32_REV_MIN_2
Expand Down
12 changes: 12 additions & 0 deletions components/esp_system/Kconfig
Expand Up @@ -531,6 +531,18 @@ menu "ESP System Settings"
# Insert chip-specific system config
rsource "./port/soc/$IDF_TARGET/Kconfig.system"

config ESP_SYSTEM_BROWNOUT_INTR
bool
default n
help
This config allows to trigger an interrupt when brownout detected. Software restart will be done
at the end of the default callback.
Two occasions need to restart the chip with interrupt so far.
(1). For ESP32 version 1, brown-out reset function doesn't work (see ESP32 errata 3.4).
So that we must restart from interrupt.
(2). For special workflow, the chip needs do more things instead of restarting directly. This part
needs to be done in callback function of interrupt.

endmenu # ESP System Settings

menu "IPC (Inter-Processor Call)"
Expand Down
56 changes: 34 additions & 22 deletions components/esp_system/port/brownout.c
Expand Up @@ -11,13 +11,17 @@

#include "esp_private/system_internal.h"
#include "esp_private/rtc_ctrl.h"
#include "esp_private/spi_flash_os.h"

#include "esp_rom_sys.h"

#include "soc/soc.h"
#include "esp_cpu.h"
#include "soc/rtc_periph.h"
#include "hal/cpu_hal.h"
#include "esp_attr.h"
#include "bootloader_flash.h"
#include "esp_intr_alloc.h"

#include "hal/brownout_hal.h"

Expand All @@ -29,48 +33,58 @@
#define BROWNOUT_DET_LVL 0
#endif

#if SOC_BROWNOUT_RESET_SUPPORTED
#define BROWNOUT_RESET_EN true
#else
#define BROWNOUT_RESET_EN false
#endif // SOC_BROWNOUT_RESET_SUPPORTED

#ifndef SOC_BROWNOUT_RESET_SUPPORTED
static void rtc_brownout_isr_handler(void *arg)
#if CONFIG_ESP_SYSTEM_BROWNOUT_INTR
IRAM_ATTR static void rtc_brownout_isr_handler(void *arg)
{
/* Normally RTC ISR clears the interrupt flag after the application-supplied
* handler returns. Since restart is called here, the flag needs to be
* cleared manually.
*/
brownout_hal_intr_clear();
/* Stall the other CPU to make sure the code running there doesn't use UART
* at the same time as the following esp_rom_printf.
*/
// Stop the other core.
esp_cpu_stall(!cpu_hal_get_core_id());
esp_reset_reason_set_hint(ESP_RST_BROWNOUT);
esp_rom_printf("\r\nBrownout detector was triggered\r\n\r\n");
#if CONFIG_SPI_FLASH_BROWNOUT_RESET
if (spi_flash_brownout_need_reset()) {
bootloader_flash_reset_chip();
} else
#endif // CONFIG_SPI_FLASH_BROWNOUT_RESET
{
esp_rom_printf("\r\nBrownout detector was triggered\r\n\r\n");
}

esp_restart_noos();
}
#endif // not SOC_BROWNOUT_RESET_SUPPORTED
#endif // CONFIG_ESP_SYSTEM_BROWNOUT_INTR

void esp_brownout_init(void)
{
#if CONFIG_ESP_SYSTEM_BROWNOUT_INTR
brownout_hal_config_t cfg = {
.threshold = BROWNOUT_DET_LVL,
.enabled = true,
.reset_enabled = BROWNOUT_RESET_EN,
.reset_enabled = false,
.flash_power_down = true,
.rf_power_down = true,
};

brownout_hal_config(&cfg);
brownout_hal_intr_clear();
rtc_isr_register(rtc_brownout_isr_handler, NULL, RTC_CNTL_BROWN_OUT_INT_ENA_M, RTC_INTR_FLAG_IRAM);
brownout_hal_intr_enable(true);

#else // brownout without interrupt

#ifndef SOC_BROWNOUT_RESET_SUPPORTED
rtc_isr_register(rtc_brownout_isr_handler, NULL, RTC_CNTL_BROWN_OUT_INT_ENA_M);
brownout_hal_config_t cfg = {
.threshold = BROWNOUT_DET_LVL,
.enabled = true,
.reset_enabled = true,
.flash_power_down = true,
.rf_power_down = true,
};

brownout_hal_intr_enable(true);
#endif // not SOC_BROWNOUT_RESET_SUPPORTED
brownout_hal_config(&cfg);
#endif
}

void esp_brownout_disable(void)
Expand All @@ -80,10 +94,8 @@ void esp_brownout_disable(void)
};

brownout_hal_config(&cfg);

#ifndef SOC_BROWNOUT_RESET_SUPPORTED
#if CONFIG_ESP_SYSTEM_BROWNOUT_INTR
brownout_hal_intr_enable(false);

rtc_isr_deregister(rtc_brownout_isr_handler, NULL);
#endif // not SOC_BROWNOUT_RESET_SUPPORTED
#endif // CONFIG_ESP_SYSTEM_BROWNOUT_INTR
}
5 changes: 4 additions & 1 deletion components/esp_system/startup.c
Expand Up @@ -66,7 +66,7 @@

#include "esp_pthread.h"
#include "esp_private/esp_clk.h"

#include "esp_private/spi_flash_os.h"
#include "esp_private/brownout.h"

#include "esp_rom_sys.h"
Expand Down Expand Up @@ -301,6 +301,9 @@ static void do_core_init(void)
esp_err_t flash_ret = esp_flash_init_default_chip();
assert(flash_ret == ESP_OK);
(void)flash_ret;
#if CONFIG_SPI_FLASH_BROWNOUT_RESET
spi_flash_needs_reset_check();
#endif // CONFIG_SPI_FLASH_BROWNOUT_RESET

#ifdef CONFIG_EFUSE_VIRTUAL
ESP_LOGW(TAG, "eFuse virtual mode is enabled. If Secure boot or Flash encryption is enabled then it does not provide any security. FOR TESTING ONLY!");
Expand Down
21 changes: 7 additions & 14 deletions components/hal/esp32/brownout_hal.c
@@ -1,20 +1,13 @@

// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/

#include "hal/brownout_hal.h"
#include "soc/rtc_cntl_struct.h"
#include "esp_attr.h"

void brownout_hal_config(const brownout_hal_config_t *cfg)
{
Expand All @@ -35,7 +28,7 @@ void brownout_hal_intr_enable(bool enable)
RTCCNTL.int_ena.rtc_brown_out = enable;
}

void brownout_hal_intr_clear(void)
IRAM_ATTR void brownout_hal_intr_clear(void)
{
RTCCNTL.int_clr.rtc_brown_out = 1;
}
3 changes: 2 additions & 1 deletion components/hal/esp32c2/brownout_hal.c
Expand Up @@ -10,6 +10,7 @@
#include "soc/rtc_cntl_reg.h"
#include "esp_private/regi2c_ctrl.h"
#include "regi2c_brownout.h"
#include "esp_attr.h"


void brownout_hal_config(const brownout_hal_config_t *cfg)
Expand All @@ -31,7 +32,7 @@ void brownout_hal_intr_enable(bool enable)
RTCCNTL.int_ena.rtc_brown_out = enable;
}

void brownout_hal_intr_clear(void)
IRAM_ATTR void brownout_hal_intr_clear(void)
{
RTCCNTL.int_clr.rtc_brown_out = 1;
}
3 changes: 2 additions & 1 deletion components/hal/esp32c3/brownout_hal.c
Expand Up @@ -10,6 +10,7 @@
#include "soc/rtc_cntl_reg.h"
#include "esp_private/regi2c_ctrl.h"
#include "regi2c_brownout.h"
#include "esp_attr.h"


void brownout_hal_config(const brownout_hal_config_t *cfg)
Expand All @@ -31,7 +32,7 @@ void brownout_hal_intr_enable(bool enable)
RTCCNTL.int_ena.rtc_brown_out = enable;
}

void brownout_hal_intr_clear(void)
IRAM_ATTR void brownout_hal_intr_clear(void)
{
RTCCNTL.int_clr.rtc_brown_out = 1;
}
3 changes: 2 additions & 1 deletion components/hal/esp32h2/brownout_hal.c
Expand Up @@ -11,6 +11,7 @@
#include "i2c_pmu.h"
#include "esp_private/regi2c_ctrl.h"
#include "regi2c_brownout.h"
#include "esp_attr.h"


void brownout_hal_config(const brownout_hal_config_t *cfg)
Expand All @@ -32,7 +33,7 @@ void brownout_hal_intr_enable(bool enable)
RTCCNTL.int_ena.rtc_brown_out = enable;
}

void brownout_hal_intr_clear(void)
IRAM_ATTR void brownout_hal_intr_clear(void)
{
RTCCNTL.int_clr.rtc_brown_out = 1;
}
4 changes: 2 additions & 2 deletions components/hal/esp32s2/brownout_hal.c
Expand Up @@ -10,7 +10,7 @@
#include "soc/rtc_cntl_reg.h"
#include "esp_private/regi2c_ctrl.h"
#include "regi2c_brownout.h"

#include "esp_attr.h"

void brownout_hal_config(const brownout_hal_config_t *cfg)
{
Expand All @@ -33,7 +33,7 @@ void brownout_hal_intr_enable(bool enable)
RTCCNTL.int_ena.rtc_brown_out = enable;
}

void brownout_hal_intr_clear(void)
IRAM_ATTR void brownout_hal_intr_clear(void)
{
RTCCNTL.int_clr.rtc_brown_out = 1;
}
3 changes: 2 additions & 1 deletion components/hal/esp32s3/brownout_hal.c
Expand Up @@ -10,6 +10,7 @@
#include "soc/rtc_cntl_reg.h"
#include "esp_private/regi2c_ctrl.h"
#include "regi2c_brownout.h"
#include "esp_attr.h"


void brownout_hal_config(const brownout_hal_config_t *cfg)
Expand All @@ -32,7 +33,7 @@ void brownout_hal_intr_enable(bool enable)
RTCCNTL.int_ena.rtc_brown_out = enable;
}

void brownout_hal_intr_clear(void)
IRAM_ATTR void brownout_hal_intr_clear(void)
{
RTCCNTL.int_clr.rtc_brown_out = 1;
}
18 changes: 5 additions & 13 deletions components/hal/include/hal/brownout_hal.h
@@ -1,16 +1,8 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/

/*******************************************************************************
* NOTICE
Expand Down
1 change: 0 additions & 1 deletion components/soc/esp32/include/soc/soc_caps.h
Expand Up @@ -127,7 +127,6 @@
#define SOC_ADC_RTC_MAX_BITWIDTH (12)
#define SOC_RTC_SLOW_CLOCK_SUPPORT_8MD256 (1)


/*-------------------------- BROWNOUT CAPS -----------------------------------*/
#if SOC_CAPS_ECO_VER >= 1
#define SOC_BROWNOUT_RESET_SUPPORTED 1
Expand Down
8 changes: 4 additions & 4 deletions components/soc/esp32s3/include/soc/Kconfig.soc_caps.in
Expand Up @@ -3,10 +3,6 @@
# using gen_soc_caps_kconfig.py, do not edit manually
#####################################################

config SOC_BROWNOUT_RESET_SUPPORTED
bool
default y

config SOC_CPU_BREAKPOINTS_NUM
int
default 2
Expand Down Expand Up @@ -287,6 +283,10 @@ config SOC_APB_BACKUP_DMA
bool
default y

config SOC_BROWNOUT_RESET_SUPPORTED
bool
default y

config SOC_DS_SIGNATURE_MAX_BIT_LEN
int
default 4096
Expand Down

0 comments on commit 6a2d350

Please sign in to comment.