Parcourir la source

spi_flash: Making XMC flash works more stable when brownout detected

Cao Sen Miao il y a 3 ans
Parent
commit
6a2d3509dc

+ 6 - 0
components/bootloader_support/bootloader_flash/include/bootloader_flash.h

@@ -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
 }

+ 41 - 0
components/bootloader_support/bootloader_flash/src/bootloader_flash.c

@@ -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 - 0
components/esp_hw_support/port/esp32/Kconfig.hw_support

@@ -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

+ 12 - 0
components/esp_system/Kconfig

@@ -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)"

+ 34 - 22
components/esp_system/port/brownout.c

@@ -11,6 +11,7 @@
 
 #include "esp_private/system_internal.h"
 #include "esp_private/rtc_ctrl.h"
+#include "esp_private/spi_flash_os.h"
 
 #include "esp_rom_sys.h"
 
@@ -18,6 +19,9 @@
 #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"
 
@@ -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)
@@ -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
 }

+ 4 - 1
components/esp_system/startup.c

@@ -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"
@@ -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!");

+ 7 - 14
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)
 {
@@ -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;
 }

+ 2 - 1
components/hal/esp32c2/brownout_hal.c

@@ -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)
@@ -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;
 }

+ 2 - 1
components/hal/esp32c3/brownout_hal.c

@@ -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)
@@ -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;
 }

+ 2 - 1
components/hal/esp32h2/brownout_hal.c

@@ -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)
@@ -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;
 }

+ 2 - 2
components/hal/esp32s2/brownout_hal.c

@@ -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)
 {
@@ -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;
 }

+ 2 - 1
components/hal/esp32s3/brownout_hal.c

@@ -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)
@@ -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;
 }

+ 5 - 13
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

+ 0 - 1
components/soc/esp32/include/soc/soc_caps.h

@@ -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

+ 4 - 4
components/soc/esp32s3/include/soc/Kconfig.soc_caps.in

@@ -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
@@ -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

+ 0 - 25
components/soc/esp32s3/include/soc/brownout_caps.h

@@ -1,25 +0,0 @@
-// 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.
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define SOC_BROWNOUT_RESET_SUPPORTED 1
-
-#ifdef __cplusplus
-}
-#endif

+ 1 - 1
components/soc/esp32s3/include/soc/soc_caps.h

@@ -100,7 +100,7 @@
 #define SOC_APB_BACKUP_DMA              (1)
 
 /*-------------------------- BROWNOUT CAPS -----------------------------------*/
-#include "brownout_caps.h"
+#define SOC_BROWNOUT_RESET_SUPPORTED 1
 
 /*-------------------------- CPU CAPS ----------------------------------------*/
 #include "cpu_caps.h"

+ 1 - 0
components/spi_flash/CMakeLists.txt

@@ -25,6 +25,7 @@ else()
     set(srcs
         "partition.c"
         "partition_target.c"
+        "flash_brownout_hook.c"
     )
 
     if(CONFIG_ESPTOOLPY_OCT_FLASH)

+ 22 - 0
components/spi_flash/Kconfig

@@ -209,6 +209,28 @@ menu "SPI Flash driver"
 
             See example: custom_chip_driver under examples/storage for more details.
 
+    menu "SPI Flash behavior when brownout"
+
+        config SPI_FLASH_BROWNOUT_RESET_XMC
+            bool "Enable sending reset when brownout for XMC flash chips"
+            default y
+            select SPI_FLASH_BROWNOUT_RESET
+            help
+                When this option is selected, the patch will be enabled for XMC.
+                Follow the recommended flow by XMC for better stability.
+
+                DO NOT DISABLE UNLESS YOU KNOW WHAT YOU ARE DOING.
+
+        config SPI_FLASH_BROWNOUT_RESET
+            bool
+            default y
+            select ESP_SYSTEM_BROWNOUT_INTR
+            help
+                When brownout happens during flash erase/write operations,
+                send reset command to stop the flash operations to improve stability.
+
+    endmenu
+
     menu "Auto-detect flash chips"
         visible if !SPI_FLASH_OVERRIDE_CHIP_DRIVER_LIST
 

+ 39 - 0
components/spi_flash/flash_brownout_hook.c

@@ -0,0 +1,39 @@
+/*
+ * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "esp_attr.h"
+#include "sdkconfig.h"
+#include "esp_rom_spiflash.h"
+
+#if CONFIG_SPI_FLASH_BROWNOUT_RESET
+
+static bool flash_brownout_needs_reset = false;
+static bool flash_erasing = false;
+
+// This function could be called in startup
+void spi_flash_needs_reset_check(void)
+{
+    // Currently only XMC is suggested to reset when brownout
+#if CONFIG_SPI_FLASH_BROWNOUT_RESET_XMC
+    if ((g_rom_flashchip.device_id >> 16) == 0x20) {
+        flash_brownout_needs_reset = true;
+    }
+#endif
+}
+
+void spi_flash_set_erasing_flag(bool status)
+{
+    flash_erasing = status;
+}
+
+bool spi_flash_brownout_need_reset(void)
+{
+    return (flash_brownout_needs_reset && flash_erasing);
+}
+
+#endif //CONFIG_SPI_FLASH_BROWNOUT_RESET

+ 10 - 13
components/spi_flash/include/esp_flash.h

@@ -1,16 +1,8 @@
-// Copyright 2015-2019 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: 2015-2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
 
 #pragma once
 #include "esp_err.h"
@@ -80,6 +72,11 @@ typedef struct {
     /** Called for get system time. */
     int64_t (*get_system_time)(void *arg);
 
+    #define SPI_FLASH_OS_IS_ERASING_STATUS_FLAG   BIT(0)
+
+    /** Call to set flash operation status */
+    void (*set_flash_op_status)(uint32_t op_status);
+
 } esp_flash_os_functions_t;
 
 /** @brief Structure to describe a SPI flash chip connected to the system.

+ 23 - 1
components/spi_flash/include/esp_private/spi_flash_os.h

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
+ * SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
  *
  * SPDX-License-Identifier: Apache-2.0
  */
@@ -101,6 +101,28 @@ bool spi_timing_is_tuned(void);
  */
 void spi_flash_set_vendor_required_regs(void);
 
+/**
+ * @brief Judge whether need to reset flash when brownout.
+ *        Set` flash_brownout_needs_reset` inside the function if really need reset.
+ */
+void spi_flash_needs_reset_check(void);
+
+/**
+ * @brief Set flag to reset flash. set when erase chip or program chip
+ *
+ * @param bool status. True if flash is eraing. False if flash is not erasing.
+ *
+ * @return None.
+ */
+void spi_flash_set_erasing_flag(bool status);
+
+/**
+ * @brief Judge whether need to reset flash when brownout.
+ *
+ * @return true if need reset, otherwise false.
+ */
+bool spi_flash_brownout_need_reset(void);
+
 /**
  * @brief Enable SPI flash high performance mode.
  *

+ 5 - 13
components/spi_flash/include/memspi_host_driver.h

@@ -1,16 +1,8 @@
-// Copyright 2015-2019 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: 2015-2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
 
 #pragma once
 #include "hal/spi_flash_hal.h"

+ 1 - 0
components/spi_flash/linker.lf

@@ -9,6 +9,7 @@ entries:
     spi_flash_chip_boya (noflash)
     spi_flash_chip_th (noflash)
     memspi_host_driver (noflash)
+    flash_brownout_hook (noflash)
 
     if IDF_TARGET_ESP32S3 = y:
         spi_flash_timing_tuning (noflash)

+ 18 - 13
components/spi_flash/spi_flash_chip_generic.c

@@ -1,16 +1,8 @@
-// Copyright 2015-2019 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: 2015-2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
 
 #include <stdlib.h>
 #include <string.h>
@@ -20,6 +12,7 @@
 #include "hal/spi_flash_encrypt_hal.h"
 #include "esp_log.h"
 #include "esp_attr.h"
+#include "esp_private/spi_flash_os.h"
 
 typedef struct flash_chip_dummy {
     uint8_t dio_dummy_bitlen;
@@ -69,6 +62,12 @@ const DRAM_ATTR flash_chip_op_timeout_t spi_flash_chip_generic_timeout = {
     .page_program_timeout = SPI_FLASH_GENERIC_PAGE_PROGRAM_TIMEOUT_MS * 1000,
 };
 
+#define SET_FLASH_ERASE_STATUS(CHIP, status) do { \
+    if (CHIP->os_func->set_flash_op_status) { \
+        CHIP->os_func->set_flash_op_status(status); \
+    } \
+} while(0)
+
 static const char TAG[] = "chip_generic";
 
 #ifndef CONFIG_SPI_FLASH_ROM_IMPL
@@ -130,6 +129,7 @@ esp_err_t spi_flash_chip_generic_erase_chip(esp_flash_t *chip)
     }
     //The chip didn't accept the previous write command. Ignore this in preparation stage.
     if (err == ESP_OK || err == ESP_ERR_NOT_SUPPORTED) {
+        SET_FLASH_ERASE_STATUS(chip, SPI_FLASH_OS_IS_ERASING_STATUS_FLAG);
         chip->host->driver->erase_chip(chip->host);
         chip->busy = 1;
 #ifdef CONFIG_SPI_FLASH_CHECK_ERASE_TIMEOUT_DISABLED
@@ -137,6 +137,7 @@ esp_err_t spi_flash_chip_generic_erase_chip(esp_flash_t *chip)
 #else
         err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->chip_erase_timeout);
 #endif
+        SET_FLASH_ERASE_STATUS(chip, 0);
     }
     // Ensure WEL is 0, even if the erase failed.
     if (err == ESP_ERR_NOT_SUPPORTED) {
@@ -154,6 +155,7 @@ esp_err_t spi_flash_chip_generic_erase_sector(esp_flash_t *chip, uint32_t start_
     }
     //The chip didn't accept the previous write command. Ignore this in preparationstage.
     if (err == ESP_OK || err == ESP_ERR_NOT_SUPPORTED) {
+        SET_FLASH_ERASE_STATUS(chip, SPI_FLASH_OS_IS_ERASING_STATUS_FLAG);
         chip->host->driver->erase_sector(chip->host, start_address);
         chip->busy = 1;
 #ifdef CONFIG_SPI_FLASH_CHECK_ERASE_TIMEOUT_DISABLED
@@ -161,6 +163,7 @@ esp_err_t spi_flash_chip_generic_erase_sector(esp_flash_t *chip, uint32_t start_
 #else
         err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->sector_erase_timeout);
 #endif
+        SET_FLASH_ERASE_STATUS(chip, 0);
     }
     // Ensure WEL is 0, even if the erase failed.
     if (err == ESP_ERR_NOT_SUPPORTED) {
@@ -178,6 +181,7 @@ esp_err_t spi_flash_chip_generic_erase_block(esp_flash_t *chip, uint32_t start_a
     }
     //The chip didn't accept the previous write command. Ignore this in preparationstage.
     if (err == ESP_OK || err == ESP_ERR_NOT_SUPPORTED) {
+        SET_FLASH_ERASE_STATUS(chip, SPI_FLASH_OS_IS_ERASING_STATUS_FLAG);
         chip->host->driver->erase_block(chip->host, start_address);
         chip->busy = 1;
 #ifdef CONFIG_SPI_FLASH_CHECK_ERASE_TIMEOUT_DISABLED
@@ -185,6 +189,7 @@ esp_err_t spi_flash_chip_generic_erase_block(esp_flash_t *chip, uint32_t start_a
 #else
         err = chip->chip_drv->wait_idle(chip, chip->chip_drv->timeout->block_erase_timeout);
 #endif
+        SET_FLASH_ERASE_STATUS(chip, 0);
     }
     // Ensure WEL is 0, even if the erase failed.
     if (err == ESP_ERR_NOT_SUPPORTED) {

+ 14 - 0
components/spi_flash/spi_flash_os_func_app.c

@@ -18,6 +18,7 @@
 #include "esp_log.h"
 #include "esp_compiler.h"
 #include "esp_rom_sys.h"
+#include "esp_private/spi_flash_os.h"
 
 #include "driver/spi_common_internal.h"
 
@@ -185,6 +186,13 @@ static IRAM_ATTR esp_err_t main_flash_region_protected(void* arg, size_t start_a
     }
 }
 
+
+static IRAM_ATTR void main_flash_op_status(uint32_t op_status)
+{
+    bool is_erasing = op_status & SPI_FLASH_OS_IS_ERASING_STATUS_FLAG;
+    spi_flash_set_erasing_flag(is_erasing);
+}
+
 static DRAM_ATTR spi1_app_func_arg_t main_flash_arg = {};
 
 //for SPI1, we have to disable the cache and interrupts before using the SPI bus
@@ -197,6 +205,11 @@ static const DRAM_ATTR esp_flash_os_functions_t esp_flash_spi1_default_os_functi
     .release_temp_buffer = release_buffer_malloc,
     .check_yield = spi1_flash_os_check_yield,
     .yield = spi1_flash_os_yield,
+#if CONFIG_SPI_FLASH_BROWNOUT_RESET
+    .set_flash_op_status = main_flash_op_status,
+#else
+    .set_flash_op_status = NULL,
+#endif
 };
 
 static const esp_flash_os_functions_t esp_flash_spi23_default_os_functions = {
@@ -208,6 +221,7 @@ static const esp_flash_os_functions_t esp_flash_spi23_default_os_functions = {
     .region_protected = NULL,
     .check_yield = NULL,
     .yield = NULL,
+    .set_flash_op_status = NULL,
 };
 
 static bool use_bus_lock(int host_id)

+ 0 - 5
tools/ci/check_copyright_ignore.txt

@@ -775,7 +775,6 @@ components/hal/aes_hal.c
 components/hal/cpu_hal.c
 components/hal/dac_hal.c
 components/hal/ds_hal.c
-components/hal/esp32/brownout_hal.c
 components/hal/esp32/gpio_hal_workaround.c
 components/hal/esp32/include/hal/aes_ll.h
 components/hal/esp32/include/hal/can_hal.h
@@ -859,7 +858,6 @@ components/hal/esp32s3/include/hal/usb_serial_jtag_ll.h
 components/hal/esp32s3/interrupt_descriptor_table.c
 components/hal/include/hal/aes_hal.h
 components/hal/include/hal/aes_types.h
-components/hal/include/hal/brownout_hal.h
 components/hal/include/hal/cpu_types.h
 components/hal/include/hal/dac_hal.h
 components/hal/include/hal/dac_types.h
@@ -1536,10 +1534,8 @@ components/soc/include/soc/usb_periph.h
 components/soc/lldesc.c
 components/soc/soc_include_legacy_warn.c
 components/spi_flash/cache_utils.h
-components/spi_flash/include/esp_flash.h
 components/spi_flash/include/esp_spi_flash.h
 components/spi_flash/include/esp_spi_flash_counters.h
-components/spi_flash/include/memspi_host_driver.h
 components/spi_flash/include/spi_flash_chip_boya.h
 components/spi_flash/include/spi_flash_chip_driver.h
 components/spi_flash/include/spi_flash_chip_gd.h
@@ -1553,7 +1549,6 @@ components/spi_flash/sim/flash_mock_util.c
 components/spi_flash/sim/sdkconfig/sdkconfig.h
 components/spi_flash/spi_flash_chip_boya.c
 components/spi_flash/spi_flash_chip_gd.c
-components/spi_flash/spi_flash_chip_generic.c
 components/spi_flash/spi_flash_chip_issi.c
 components/spi_flash/spi_flash_chip_mxic.c
 components/spi_flash/spi_flash_chip_mxic_opi.c