|
|
@@ -17,10 +17,12 @@
|
|
|
#include <xtensa/corebits.h>
|
|
|
#include <xtensa/config/system.h>
|
|
|
#include "freertos/xtensa_context.h"
|
|
|
+#include "freertos/xtensa_rtos.h"
|
|
|
#include "esp_private/panic_reason.h"
|
|
|
#include "sdkconfig.h"
|
|
|
#include "soc/soc.h"
|
|
|
#include "soc/dport_reg.h"
|
|
|
+#include "soc/timer_group_reg.h"
|
|
|
|
|
|
/*
|
|
|
|
|
|
@@ -37,7 +39,23 @@ Interrupt , a high-priority interrupt, is used for several things:
|
|
|
#define L4_INTR_A4_OFFSET 8
|
|
|
.data
|
|
|
_l4_intr_stack:
|
|
|
- .space L4_INTR_STACK_SIZE
|
|
|
+ .space L4_INTR_STACK_SIZE*portNUM_PROCESSORS /* This allocates stacks for each individual CPU. */
|
|
|
+
|
|
|
+#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_ESP_INT_WDT
|
|
|
+ .global _l4_intr_livelock_counter
|
|
|
+ .global _l4_intr_livelock_max
|
|
|
+ .align 16
|
|
|
+_l4_intr_livelock_counter:
|
|
|
+ .word 0
|
|
|
+_l4_intr_livelock_max:
|
|
|
+ .word 0
|
|
|
+_l4_intr_livelock_sync:
|
|
|
+ .word 0, 0
|
|
|
+_l4_intr_livelock_app:
|
|
|
+ .word 0
|
|
|
+_l4_intr_livelock_pro:
|
|
|
+ .word 0
|
|
|
+#endif
|
|
|
|
|
|
.section .iram1,"ax"
|
|
|
.global xt_highint4
|
|
|
@@ -52,8 +70,24 @@ xt_highint4:
|
|
|
bnez a0, .handle_dport_access_int
|
|
|
#endif // CONFIG_FREERTOS_UNICORE
|
|
|
|
|
|
+#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_ESP_INT_WDT
|
|
|
+ /* See if we're here for the tg1 watchdog interrupt */
|
|
|
+ rsr a0, INTERRUPT
|
|
|
+ extui a0, a0, ETS_T1_WDT_INUM, 1
|
|
|
+ beqz a0, 1f
|
|
|
+
|
|
|
+ wsr a5, depc /* use DEPC as temp storage */
|
|
|
+ movi a0, _l4_intr_livelock_counter
|
|
|
+ l32i a0, a0, 0
|
|
|
+ movi a5, _l4_intr_livelock_max
|
|
|
+ l32i a5, a5, 0
|
|
|
+ bltu a0, a5, .handle_livelock_int /* _l4_intr_livelock_counter < _l4_intr_livelock_max */
|
|
|
+
|
|
|
+ rsr a5, depc /* restore a5 */
|
|
|
+#endif
|
|
|
+
|
|
|
/* Allocate exception frame and save minimal context. */
|
|
|
- mov a0, sp
|
|
|
+1: mov a0, sp
|
|
|
addi sp, sp, -XT_STK_FRMSZ
|
|
|
s32i a0, sp, XT_STK_A1
|
|
|
#if XCHAL_HAVE_WINDOWED
|
|
|
@@ -129,6 +163,257 @@ xt_highint4:
|
|
|
rfi 4
|
|
|
|
|
|
|
|
|
+#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_ESP_INT_WDT
|
|
|
+
|
|
|
+/*
|
|
|
+--------------------------------------------------------------------------------
|
|
|
+ Macro intr_matrix_map - Attach an CPU interrupt to a hardware source.
|
|
|
+
|
|
|
+ Input : "addr" - Interrupt map configuration base address
|
|
|
+ Input : "src" - Interrupt source.
|
|
|
+ Input : "inum" - Interrupt number.
|
|
|
+--------------------------------------------------------------------------------
|
|
|
+*/
|
|
|
+ .macro intr_matrix_map addr src inum
|
|
|
+ movi a2, \src
|
|
|
+ slli a2, a2, 2
|
|
|
+ movi a3, \addr
|
|
|
+ add a3, a3, a2
|
|
|
+ movi a2, \inum
|
|
|
+ s32i a2, a3, 0
|
|
|
+ memw
|
|
|
+ .endm
|
|
|
+
|
|
|
+/*
|
|
|
+--------------------------------------------------------------------------------
|
|
|
+ Macro wdt_clr_intr_status - Clear the WDT interrupt status.
|
|
|
+ Macro wdt_feed - Feed the WDT.
|
|
|
+
|
|
|
+ Input : "dev" - Beginning address of the peripheral registers
|
|
|
+--------------------------------------------------------------------------------
|
|
|
+*/
|
|
|
+
|
|
|
+#define TIMG1_REG_OFFSET(reg) ((reg) - REG_TIMG_BASE(1))
|
|
|
+#define TIMG1_WDTWPROTECT_OFFSET TIMG1_REG_OFFSET(TIMG_WDTWPROTECT_REG(1))
|
|
|
+#define TIMG1_INT_CLR_OFFSET TIMG1_REG_OFFSET(TIMG_INT_CLR_TIMERS_REG(1))
|
|
|
+#define TIMG1_WDT_STG0_HOLD_OFFSET TIMG1_REG_OFFSET(TIMG_WDTCONFIG2_REG(1))
|
|
|
+#define TIMG1_WDT_STG1_HOLD_OFFSET TIMG1_REG_OFFSET(TIMG_WDTCONFIG3_REG(1))
|
|
|
+#define TIMG1_WDT_FEED_OFFSET TIMG1_REG_OFFSET(TIMG_WDTFEED_REG(1))
|
|
|
+
|
|
|
+ .macro wdt_clr_intr_status dev
|
|
|
+ movi a2, \dev
|
|
|
+ movi a3, TIMG_WDT_WKEY_VALUE
|
|
|
+ s32i a3, a2, TIMG1_WDTWPROTECT_OFFSET /* disable write protect */
|
|
|
+ memw
|
|
|
+ l32i a4, a2, TIMG1_INT_CLR_OFFSET
|
|
|
+ memw
|
|
|
+ movi a3, 4
|
|
|
+ or a3, a4, a3
|
|
|
+ s32i a3, a2, TIMG1_INT_CLR_OFFSET /* clear 1st stage timeout interrupt */
|
|
|
+ memw
|
|
|
+ movi a3, 0
|
|
|
+ s32i a3, a2, TIMG1_WDTWPROTECT_OFFSET /* enable write protect */
|
|
|
+ memw
|
|
|
+ .endm
|
|
|
+
|
|
|
+ .macro wdt_feed dev
|
|
|
+ movi a2, \dev
|
|
|
+ movi a3, TIMG_WDT_WKEY_VALUE
|
|
|
+ s32i a3, a2, TIMG1_WDTWPROTECT_OFFSET /* disable write protect */
|
|
|
+ memw
|
|
|
+ movi a4, _l4_intr_livelock_max
|
|
|
+ l32i a4, a4, 0
|
|
|
+ memw
|
|
|
+ addi a4, a4, 1
|
|
|
+ movi a3, (CONFIG_ESP_INT_WDT_TIMEOUT_MS<<1)
|
|
|
+ quou a3, a3, a4
|
|
|
+ s32i a3, a2, TIMG1_WDT_STG0_HOLD_OFFSET /* set timeout before interrupt */
|
|
|
+ memw
|
|
|
+ movi a3, (CONFIG_ESP_INT_WDT_TIMEOUT_MS<<2)
|
|
|
+ s32i a3, a2, TIMG1_WDT_STG1_HOLD_OFFSET /* set timeout before system reset */
|
|
|
+ memw
|
|
|
+ movi a3, 1
|
|
|
+ s32i a3, a2, TIMG1_WDT_FEED_OFFSET /* feed wdt */
|
|
|
+ memw
|
|
|
+ movi a3, 0
|
|
|
+ s32i a3, a2, TIMG1_WDTWPROTECT_OFFSET /* enable write protect */
|
|
|
+ memw
|
|
|
+ .endm
|
|
|
+
|
|
|
+ .align 4
|
|
|
+.handle_livelock_int:
|
|
|
+
|
|
|
+ getcoreid a5
|
|
|
+
|
|
|
+ /* Save A2, A3, A4 so we can use those registers */
|
|
|
+ movi a0, L4_INTR_STACK_SIZE
|
|
|
+ mull a5, a5, a0
|
|
|
+ movi a0, _l4_intr_stack
|
|
|
+ add a0, a0, a5
|
|
|
+ s32i a2, a0, L4_INTR_A2_OFFSET
|
|
|
+ s32i a3, a0, L4_INTR_A3_OFFSET
|
|
|
+ s32i a4, a0, L4_INTR_A4_OFFSET
|
|
|
+
|
|
|
+ /* Here, we can use a0, a2, a3, a4, a5 registers */
|
|
|
+ getcoreid a5
|
|
|
+
|
|
|
+ rsil a0, CONFIG_ESP32_DPORT_DIS_INTERRUPT_LVL /* disable nested interrupt */
|
|
|
+
|
|
|
+ beqz a5, 1f
|
|
|
+ movi a2, _l4_intr_livelock_app
|
|
|
+ l32i a3, a2, 0
|
|
|
+ addi a3, a3, 1
|
|
|
+ s32i a3, a2, 0
|
|
|
+
|
|
|
+ /* Dual core synchronization, ensuring that both cores enter interrupts */
|
|
|
+1: movi a4, 0x1
|
|
|
+ movi a2, _l4_intr_livelock_sync
|
|
|
+ addx4 a3, a5, a2
|
|
|
+ s32i a4, a3, 0
|
|
|
+
|
|
|
+1: movi a2, _l4_intr_livelock_sync
|
|
|
+ movi a3, 1
|
|
|
+ addx4 a3, a3, a2
|
|
|
+ l32i a2, a2, 0
|
|
|
+ l32i a3, a3, 0
|
|
|
+ and a2, a2, a3
|
|
|
+ beqz a2, 1b
|
|
|
+
|
|
|
+ beqz a5, 1f /* Pro cpu (Core 0) jump bypass */
|
|
|
+
|
|
|
+ movi a2, _l4_intr_livelock_app
|
|
|
+ l32i a2, a2, 0
|
|
|
+ bnei a2, 2, 1f
|
|
|
+ movi a2, _l4_intr_livelock_counter /* _l4_intr_livelock_counter++ */
|
|
|
+ l32i a3, a2, 0
|
|
|
+ addi a3, a3, 1
|
|
|
+ s32i a3, a2, 0
|
|
|
+
|
|
|
+ /*
|
|
|
+ The delay time can be calculated by the following formula:
|
|
|
+ T = ceil(0.25 + max(t1, t2)) us
|
|
|
+
|
|
|
+ t1 = 80 / f1, t2 = (1 + 14/N) * 20 / f2
|
|
|
+
|
|
|
+ f1: PSRAM access frequency, unit: MHz.
|
|
|
+ f2: Flash access frequency, unit: MHz.
|
|
|
+
|
|
|
+ When flash is slow/fast read, N = 1.
|
|
|
+ When flash is DOUT/DIO read, N = 2.
|
|
|
+ When flash is QOUT/QIO read, N = 4.
|
|
|
+ */
|
|
|
+1: rsr.ccount a2
|
|
|
+#if defined(CONFIG_ESPTOOLPY_FLASHMODE_QIO) || defined(CONFIG_ESPTOOLPY_FLASHMODE_QOUT)
|
|
|
+# if defined(CONFIG_ESPTOOLPY_FLASHFREQ_80M) && defined(CONFIG_SPIRAM_SPEED_80M)
|
|
|
+ movi a3, 240
|
|
|
+# elif defined(CONFIG_ESPTOOLPY_FLASHFREQ_80M) && defined(CONFIG_SPIRAM_SPEED_40M)
|
|
|
+ movi a3, 720
|
|
|
+# elif defined(CONFIG_ESPTOOLPY_FLASHFREQ_40M) && defined(CONFIG_SPIRAM_SPEED_40M)
|
|
|
+ movi a3, 720
|
|
|
+# elif defined(CONFIG_ESPTOOLPY_FLASHFREQ_26M) && defined(CONFIG_SPIRAM_SPEED_40M)
|
|
|
+ movi a3, 960
|
|
|
+# else
|
|
|
+ movi a3, 1200
|
|
|
+# endif
|
|
|
+#elif defined(CONFIG_ESPTOOLPY_FLASHMODE_DIO) || defined(CONFIG_ESPTOOLPY_FLASHMODE_DOUT)
|
|
|
+# if defined(CONFIG_ESPTOOLPY_FLASHFREQ_80M) && defined(CONFIG_SPIRAM_SPEED_80M)
|
|
|
+ movi a3, 720
|
|
|
+# elif defined(CONFIG_ESPTOOLPY_FLASHFREQ_80M) && defined(CONFIG_SPIRAM_SPEED_40M)
|
|
|
+ movi a3, 720
|
|
|
+# elif defined(CONFIG_ESPTOOLPY_FLASHFREQ_40M) && defined(CONFIG_SPIRAM_SPEED_40M)
|
|
|
+ movi a3, 1200
|
|
|
+# elif defined(CONFIG_ESPTOOLPY_FLASHFREQ_26M) && defined(CONFIG_SPIRAM_SPEED_40M)
|
|
|
+ movi a3, 1680
|
|
|
+# else
|
|
|
+ movi a3, 2160
|
|
|
+# endif
|
|
|
+#endif
|
|
|
+2: rsr.ccount a4 /* delay_us(N) */
|
|
|
+ sub a4, a4, a2
|
|
|
+ bltu a4, a3, 2b
|
|
|
+
|
|
|
+ beqz a5, 2f
|
|
|
+ movi a2, _l4_intr_livelock_app
|
|
|
+ l32i a2, a2, 0
|
|
|
+ beqi a2, 2, 8f
|
|
|
+ j 3f
|
|
|
+
|
|
|
+2: movi a2, _l4_intr_livelock_pro
|
|
|
+ l32i a4, a2, 0
|
|
|
+ addi a4, a4, 1
|
|
|
+ s32i a4, a2, 0
|
|
|
+
|
|
|
+ movi a2, _l4_intr_livelock_sync
|
|
|
+ movi a3, 1
|
|
|
+ addx4 a3, a3, a2
|
|
|
+ l32i a2, a2, 0
|
|
|
+ l32i a3, a3, 0
|
|
|
+ and a2, a2, a3
|
|
|
+ beqz a2, 5f
|
|
|
+ j 1b
|
|
|
+5: bgei a4, 2, 4f
|
|
|
+ j 1b
|
|
|
+
|
|
|
+ /*
|
|
|
+ Pro cpu (Core 0) jump bypass, continue waiting, App cpu (Core 1)
|
|
|
+ can execute to here, unmap itself tg1 1st stage timeout interrupt
|
|
|
+ then restore registers and exit highint4.
|
|
|
+ */
|
|
|
+3: intr_matrix_map DPORT_APP_MAC_INTR_MAP_REG, ETS_TG1_WDT_LEVEL_INTR_SOURCE, 16
|
|
|
+ j 9f
|
|
|
+
|
|
|
+ /*
|
|
|
+ Here, App cpu (Core 1) has exited isr, Pro cpu (Core 0) help the
|
|
|
+ App cpu map tg1 1st stage timeout interrupt clear tg1 interrupt.
|
|
|
+ */
|
|
|
+4: intr_matrix_map DPORT_APP_MAC_INTR_MAP_REG, ETS_TG1_WDT_LEVEL_INTR_SOURCE, ETS_T1_WDT_INUM
|
|
|
+
|
|
|
+1: movi a2, _l4_intr_livelock_sync
|
|
|
+ movi a4, 1
|
|
|
+ addx4 a3, a4, a2
|
|
|
+ l32i a2, a2, 0
|
|
|
+ l32i a3, a3, 0
|
|
|
+ and a2, a2, a3
|
|
|
+ beqz a2, 1b /* Wait for App cpu to enter highint4 again */
|
|
|
+
|
|
|
+ wdt_clr_intr_status TIMERG1
|
|
|
+ j 9f
|
|
|
+
|
|
|
+ /* Feed watchdog */
|
|
|
+8: wdt_feed TIMERG1
|
|
|
+
|
|
|
+9: wsr a0, PS /* restore iterrupt level */
|
|
|
+
|
|
|
+ movi a0, 0
|
|
|
+ beqz a5, 1f
|
|
|
+ movi a2, _l4_intr_livelock_app
|
|
|
+ l32i a3, a2, 0
|
|
|
+ bnei a3, 2, 1f
|
|
|
+ s32i a0, a2, 0
|
|
|
+
|
|
|
+1: bnez a5, 2f
|
|
|
+ movi a2, _l4_intr_livelock_pro
|
|
|
+ s32i a0, a2, 0
|
|
|
+2: movi a2, _l4_intr_livelock_sync
|
|
|
+ addx4 a2, a5, a2
|
|
|
+ s32i a0, a2, 0
|
|
|
+
|
|
|
+ /* Done. Restore registers and return. */
|
|
|
+ movi a0, L4_INTR_STACK_SIZE
|
|
|
+ mull a5, a5, a0
|
|
|
+ movi a0, _l4_intr_stack
|
|
|
+ add a0, a0, a5
|
|
|
+ l32i a2, a0, L4_INTR_A2_OFFSET
|
|
|
+ l32i a3, a0, L4_INTR_A3_OFFSET
|
|
|
+ l32i a4, a0, L4_INTR_A4_OFFSET
|
|
|
+ rsync /* ensure register restored */
|
|
|
+
|
|
|
+ rsr a5, depc
|
|
|
+
|
|
|
+ rsr a0, EXCSAVE_4 /* restore a0 */
|
|
|
+ rfi 4
|
|
|
+
|
|
|
+#endif
|
|
|
|
|
|
|
|
|
#ifndef CONFIG_FREERTOS_UNICORE
|