1// Copyright 2015-2017 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
16#include <xtensa/coreasm.h>
17#include <xtensa/corebits.h>
18#include <xtensa/config/system.h>
19#include "freertos/xtensa_context.h"
20#include "freertos/xtensa_rtos.h"
21#include "esp_private/panic_reason.h"
22#include "sdkconfig.h"
23#include "soc/soc.h"
24#include "soc/dport_reg.h"
25#include "soc/timer_group_reg.h"
26
27/*
28
29Interrupt , a high-priority interrupt, is used for several things:
30- IPC_ISR handler
31- Cache error panic handler
32- Interrupt watchdog panic handler
33
34*/
35
36#if CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5
37
38#define LX_INTR_STACK_SIZE  12
39#define LX_INTR_A2_OFFSET   0
40#define LX_INTR_A3_OFFSET   4
41#define LX_INTR_A4_OFFSET   8
42#define EPC_X               EPC_5
43#define EXCSAVE_X           EXCSAVE_5
44#define RFI_X               5
45#define xt_highintx         xt_highint5
46
47#elif CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_4
48
49#define LX_INTR_STACK_SIZE  12
50#define LX_INTR_A2_OFFSET   0
51#define LX_INTR_A3_OFFSET   4
52#define LX_INTR_A4_OFFSET   8
53#define EPC_X               EPC_4
54#define EXCSAVE_X           EXCSAVE_4
55#define RFI_X               4
56#define xt_highintx         xt_highint4
57
58#endif /* CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5 */
59
60/*
61--------------------------------------------------------------------------------
62  Macro wdt_clr_intr_status - Clear the WDT interrupt status.
63  Macro wdt_feed            - Feed the WDT.
64
65  Input  : "dev" - Beginning address of the peripheral registers
66
67  Macro get_int_status_tg1wdt - Get the ETS_TG1_WDT_LEVEL_INTR_SOURCE bit in interrupt status
68
69  output  : "reg" - Store the result into the reg
70--------------------------------------------------------------------------------
71*/
72
73#define TIMG1_REG_OFFSET(reg)               ((reg) - REG_TIMG_BASE(1))
74#define TIMG1_WDTWPROTECT_OFFSET            TIMG1_REG_OFFSET(TIMG_WDTWPROTECT_REG(1))
75#define TIMG1_INT_CLR_OFFSET                TIMG1_REG_OFFSET(TIMG_INT_CLR_TIMERS_REG(1))
76#define TIMG1_WDT_STG0_HOLD_OFFSET          TIMG1_REG_OFFSET(TIMG_WDTCONFIG2_REG(1))
77#define TIMG1_WDT_STG1_HOLD_OFFSET          TIMG1_REG_OFFSET(TIMG_WDTCONFIG3_REG(1))
78#define TIMG1_WDT_FEED_OFFSET               TIMG1_REG_OFFSET(TIMG_WDTFEED_REG(1))
79#define UART0_DATA_REG                      (0x3FF40078)
80
81    .macro wdt_clr_intr_status  dev
82    movi    a2, \dev
83    movi    a3, TIMG_WDT_WKEY_VALUE
84    s32i    a3, a2, TIMG1_WDTWPROTECT_OFFSET    /* disable write protect */
85    memw
86    l32i    a4, a2, TIMG1_INT_CLR_OFFSET
87    memw
88    movi    a3, 4
89    or      a3, a4, a3
90    s32i    a3, a2, TIMG1_INT_CLR_OFFSET        /* clear 1st stage timeout interrupt */
91    memw
92    movi    a3, 0
93    s32i    a3, a2, TIMG1_WDTWPROTECT_OFFSET    /* enable write protect */
94    memw
95    .endm
96
97    .macro wdt_feed dev
98    movi    a2, \dev
99    movi    a3, TIMG_WDT_WKEY_VALUE
100    s32i    a3, a2, TIMG1_WDTWPROTECT_OFFSET    /* disable write protect */
101    memw
102    movi    a4, _lx_intr_livelock_max
103    l32i    a4, a4, 0
104    memw
105    addi    a4, a4, 1
106    movi    a3, (CONFIG_ESP_INT_WDT_TIMEOUT_MS<<1)
107    quou    a3, a3, a4
108    s32i    a3, a2, TIMG1_WDT_STG0_HOLD_OFFSET  /* set timeout before interrupt */
109    memw
110    movi    a3, (CONFIG_ESP_INT_WDT_TIMEOUT_MS<<2)
111    s32i    a3, a2, TIMG1_WDT_STG1_HOLD_OFFSET  /* set timeout before system reset */
112    memw
113    movi    a3, 1
114    s32i    a3, a2, TIMG1_WDT_FEED_OFFSET       /* feed wdt */
115    memw
116    movi    a3, 0
117    s32i    a3, a2, TIMG1_WDTWPROTECT_OFFSET    /* enable write protect */
118    memw
119    .endm
120
121    .macro get_int_status_tg1wdt reg
122    rsr     \reg, INTERRUPT
123    extui   \reg, \reg, ETS_T1_WDT_CACHEERR_INUM, 1
124    beqz    \reg, 99f        /* not ETS_T1_WDT_INUM or ETS_CACHEERR_INUM */
125
126    getcoreid   \reg
127    bnez    \reg, 98f
128    /* core 0 */
129    movi    \reg, UART0_DATA_REG
130    l32i    \reg, \reg, 0     /* Workaround for DPORT read error, for silicon revision 0~2 (ECO V0 ~ ECO V2). */
131    movi    \reg, DPORT_PRO_INTR_STATUS_0_REG
132    l32i    \reg, \reg, 0
133    extui   \reg, \reg, ETS_TG1_WDT_LEVEL_INTR_SOURCE, 1
134    j       99f
135
13698: /* core 1 */
137    movi    \reg, UART0_DATA_REG
138    l32i    \reg, \reg, 0     /* Workaround for DPORT read error, for silicon revision 0~2 (ECO V0 ~ ECO V2). */
139    movi    \reg, DPORT_APP_INTR_STATUS_0_REG
140    l32i    \reg, \reg, 0
141    extui   \reg, \reg, ETS_TG1_WDT_LEVEL_INTR_SOURCE, 1
14299:
143    .endm
144
145    .data
146_lx_intr_stack:
147    .space      LX_INTR_STACK_SIZE*portNUM_PROCESSORS /* This allocates stacks for each individual CPU. */
148
149#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_ESP_INT_WDT
150    .global _lx_intr_livelock_counter
151    .global _lx_intr_livelock_max
152    .align  16
153_lx_intr_livelock_counter:
154    .word   0
155_lx_intr_livelock_max:
156    .word   0
157_lx_intr_livelock_sync:
158    .word   0, 0
159_lx_intr_livelock_app:
160    .word   0
161_lx_intr_livelock_pro:
162    .word   0
163#endif
164
165    .section .iram1,"ax"
166    .global     xt_highintx
167    .type       xt_highintx,@function
168    .align      4
169xt_highintx:
170
171#ifndef CONFIG_FREERTOS_UNICORE
172    /* See if we're here for the IPC_ISR interrupt */
173    rsr     a0, INTERRUPT
174    extui   a0, a0, ETS_IPC_ISR_INUM, 1
175    beqz    a0, 1f
176    /* Jump to `esp_ipc_isr_handler` which is non-returning. We need to use `jx`
177     * because on Xtensa, `j` instruction can only refer to a label which
178     * is in the range [-131068;+131075]. If the destination is out of scope,
179     * linking will fail. So, to make sure we will always be able to jump to
180     * that subroutine, retrieve its address and store it in a register. */
181    movi    a0, esp_ipc_isr_handler
182    jx      a0
1831:
184#endif /* not CONFIG_FREERTOS_UNICORE */
185
186#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_ESP_INT_WDT
187
188#if CONFIG_BTDM_CTRL_HLI
189    /* Timer 2 interrupt */
190    rsr     a0, INTENABLE
191    extui   a0, a0, 16, 1
192    beqz    a0, 1f
193    rsr     a0, INTERRUPT
194    extui   a0, a0, 16, 1
195    bnez    a0, .handle_multicore_debug_int
1961:
197#endif /* CONFIG_BTDM_CTRL_HLI */
198
199    /* ETS_T1_WDT_INUM */
200#if CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5
201    get_int_status_tg1wdt a0
202#elif CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_4
203    /* See if we're here for the tg1 watchdog interrupt */
204    rsr     a0, INTERRUPT
205    extui   a0, a0, ETS_T1_WDT_INUM, 1
206#endif /* CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5 */
207    beqz    a0, 1f
208
209    wsr     a5, depc                        /* use DEPC as temp storage */
210    movi    a0, _lx_intr_livelock_counter
211    l32i    a0, a0, 0
212    movi    a5, _lx_intr_livelock_max
213    l32i    a5, a5, 0
214    bltu    a0, a5, .handle_livelock_int    /* _lx_intr_livelock_counter < _lx_intr_livelock_max */
215
216    rsr     a5, depc                        /* restore a5 */
217#endif
218
2191:  /* ETS_CACHEERR_INUM or ETS_T1_WDT_INUM */
220    /* Allocate exception frame and save minimal context. */
221    mov     a0, sp
222    addi    sp, sp, -XT_STK_FRMSZ
223    s32i    a0, sp, XT_STK_A1
224    #if XCHAL_HAVE_WINDOWED
225    s32e    a0, sp, -12                     /* for debug backtrace */
226    #endif
227    rsr     a0, PS                          /* save interruptee's PS */
228    s32i    a0, sp, XT_STK_PS
229    rsr     a0, EPC_X                       /* save interruptee's PC */
230    s32i    a0, sp, XT_STK_PC
231    #if XCHAL_HAVE_WINDOWED
232    s32e    a0, sp, -16                     /* for debug backtrace */
233    #endif
234    s32i    a12, sp, XT_STK_A12             /* _xt_context_save requires A12- */
235    s32i    a13, sp, XT_STK_A13             /* A13 to have already been saved */
236    call0   _xt_context_save
237
238    /* Save vaddr into exception frame */
239    rsr     a0, EXCVADDR
240    s32i    a0, sp, XT_STK_EXCVADDR
241
242    /* Figure out reason, save into EXCCAUSE reg */
243#if CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5
244    get_int_status_tg1wdt a0
245    bnez    a0, 1f
246
247    /* TODO: Clear the MEMACCESS_ERR interrupt status. */
248#elif CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_4
249    rsr     a0, INTERRUPT
250    extui   a0, a0, ETS_MEMACCESS_ERR_INUM, 1 /* get cacheerr int bit */
251    beqz    a0, 1f
252#endif /* CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5 */
253
254    /* Kill this interrupt; we cannot reset it. */
255    rsr     a0, INTENABLE
256    movi    a4, ~(1<<ETS_MEMACCESS_ERR_INUM)
257    and     a0, a4, a0
258    wsr     a0, INTENABLE
259    movi    a0, PANIC_RSN_CACHEERR
260    j 9f
2611:
262#if CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5
263   /* Clear the WDT interrupt status. */
264    wdt_clr_intr_status TIMERG1
265#endif /* CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5 */
266#if CONFIG_ESP_INT_WDT_CHECK_CPU1
267    /* Check if the cause is the app cpu failing to tick.*/
268    movi    a0, int_wdt_app_cpu_ticked
269    l32i    a0, a0, 0
270    bnez    a0, 2f
271    /* It is. Modify cause. */
272    movi    a0,PANIC_RSN_INTWDT_CPU1
273    j 9f
2742:
275#endif
276    /* Set EXCCAUSE to reflect cause of the wdt int trigger */
277    movi    a0,PANIC_RSN_INTWDT_CPU0
2789:
279    /* Found the reason, now save it. */
280    s32i    a0, sp, XT_STK_EXCCAUSE
281
282    /* _xt_context_save seems to save the current a0, but we need the interuptees a0. Fix this. */
283    rsr     a0, EXCSAVE_X                   /* save interruptee's a0 */
284
285    s32i    a0, sp, XT_STK_A0
286
287    /* Set up PS for C, disable all interrupts except NMI and debug, and clear EXCM. */
288    movi    a0, PS_INTLEVEL(5) | PS_UM | PS_WOE
289    wsr     a0, PS
290
291    /* Call panic handler */
292    mov     a6,sp
293    call4   panicHandler
294
295    call0   _xt_context_restore
296    l32i    a0, sp, XT_STK_PS               /* retrieve interruptee's PS */
297    wsr     a0, PS
298    l32i    a0, sp, XT_STK_PC               /* retrieve interruptee's PC */
299    wsr     a0, EPC_X
300    l32i    a0, sp, XT_STK_A0               /* retrieve interruptee's A0 */
301    l32i    sp, sp, XT_STK_A1               /* remove exception frame */
302    rsync                                   /* ensure PS and EPC written */
303
304    rsr     a0, EXCSAVE_X                   /* restore a0 */
305    rfi     RFI_X
306
307
308#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_ESP_INT_WDT
309#if CONFIG_BTDM_CTRL_HLI
310#define APB_ITCTRL              (0x3f00)
311#define APB_DCRSET              (0x200c)
312
313#define ERI_ADDR(APB)           (0x100000 + (APB))
314
315    .align      4
316.handle_multicore_debug_int:
317
318    wsr     a2, depc                        /* temp storage */
319
320    rsr.ccount  a2
321    addmi   a2, a2, (CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ*50)
322    wsr     a2, CCOMPARE2
323
324    /* Enable Integration Mode */
325    movi    a2, ERI_ADDR(APB_ITCTRL)
326    rer     a0, a2
327    addi    a0, a0, 1
328    wer     a0, a2
329
330    /* Enable and emit BreakOut signal */
331    movi    a2, ERI_ADDR(APB_DCRSET)
332    rer     a0, a2
333    movi    a2, 0x1020000
334    or      a0, a2, a0
335    movi    a2, ERI_ADDR(APB_DCRSET)
336    wer     a0, a2
337
338    .rept   4
339    nop
340    .endr
341
342    /* Enable Normal Mode */
343    movi    a2, ERI_ADDR(APB_ITCTRL)
344    rer     a0, a2
345    movi    a2, ~0x1
346    and     a0, a2, a0
347    movi    a2, ERI_ADDR(APB_ITCTRL)
348    wer     a0, a2
349
350    rsr     a2, depc
351
352    rsr     a0, EXCSAVE_5                   /* restore a0 */
353    rfi     5
354#endif /* CONFIG_BTDM_CTRL_HLI */
355
356/*
357--------------------------------------------------------------------------------
358  Macro intr_matrix_map - Attach an CPU interrupt to a hardware source.
359
360  Input  : "addr" - Interrupt map configuration base address
361  Input  : "src"  - Interrupt source.
362  Input  : "inum" - Interrupt number.
363--------------------------------------------------------------------------------
364*/
365    .macro intr_matrix_map  addr src inum
366    movi    a2, \src
367    slli    a2, a2, 2
368    movi    a3, \addr
369    add     a3, a3, a2
370    movi    a2, \inum
371    s32i    a2, a3, 0
372    memw
373    .endm
374
375
376
377    .align      4
378.handle_livelock_int:
379
380    getcoreid   a5
381
382    /* Save A2, A3, A4 so we can use those registers */
383    movi    a0, LX_INTR_STACK_SIZE
384    mull    a5, a5, a0
385    movi    a0, _lx_intr_stack
386    add     a0, a0, a5
387    s32i    a2, a0, LX_INTR_A2_OFFSET
388    s32i    a3, a0, LX_INTR_A3_OFFSET
389    s32i    a4, a0, LX_INTR_A4_OFFSET
390
391    /* Here, we can use a0, a2, a3, a4, a5 registers */
392    getcoreid   a5
393
394    rsil    a0, CONFIG_ESP32_DPORT_DIS_INTERRUPT_LVL /* disable nested interrupt */
395
396    beqz    a5, 1f
397    movi    a2, _lx_intr_livelock_app
398    l32i    a3, a2, 0
399    addi    a3, a3, 1
400    s32i    a3, a2, 0
401
402    /* Dual core synchronization, ensuring that both cores enter interrupts */
4031:  movi    a4, 0x1
404    movi    a2, _lx_intr_livelock_sync
405    addx4   a3, a5, a2
406    s32i    a4, a3, 0
407
4081:  movi    a2, _lx_intr_livelock_sync
409    movi    a3, 1
410    addx4   a3, a3, a2
411    l32i    a2, a2, 0
412    l32i    a3, a3, 0
413    and     a2, a2, a3
414    beqz    a2, 1b
415
416    beqz    a5, 1f                          /* Pro cpu (Core 0) jump bypass */
417
418    movi    a2, _lx_intr_livelock_app
419    l32i    a2, a2, 0
420    bnei    a2, 2, 1f
421    movi    a2, _lx_intr_livelock_counter   /* _lx_intr_livelock_counter++ */
422    l32i    a3, a2, 0
423    addi    a3, a3, 1
424    s32i    a3, a2, 0
425
426    /*
427    The delay time can be calculated by the following formula:
428      T = ceil(0.25 + max(t1, t2)) us
429
430      t1 = 80 / f1, t2 = (1 + 14/N) * 20 / f2
431
432      f1: PSRAM access frequency, unit: MHz.
433      f2: Flash access frequency, unit: MHz.
434
435      When flash is slow/fast read, N = 1.
436      When flash is DOUT/DIO read, N = 2.
437      When flash is QOUT/QIO read, N = 4.
438    */
4391:  rsr.ccount  a2
440#if defined(CONFIG_ESPTOOLPY_FLASHMODE_QIO) || defined(CONFIG_ESPTOOLPY_FLASHMODE_QOUT)
441# if defined(CONFIG_ESPTOOLPY_FLASHFREQ_80M) && defined(CONFIG_SPIRAM_SPEED_80M)
442    movi    a3, 480
443# elif defined(CONFIG_ESPTOOLPY_FLASHFREQ_80M) && defined(CONFIG_SPIRAM_SPEED_40M)
444    movi    a3, 720
445# elif defined(CONFIG_ESPTOOLPY_FLASHFREQ_40M) && defined(CONFIG_SPIRAM_SPEED_40M)
446    movi    a3, 720
447# elif defined(CONFIG_ESPTOOLPY_FLASHFREQ_26M) && defined(CONFIG_SPIRAM_SPEED_40M)
448    movi    a3, 960
449# else
450    movi    a3, 1200
451# endif
452#elif defined(CONFIG_ESPTOOLPY_FLASHMODE_DIO) || defined(CONFIG_ESPTOOLPY_FLASHMODE_DOUT)
453# if defined(CONFIG_ESPTOOLPY_FLASHFREQ_80M) && defined(CONFIG_SPIRAM_SPEED_80M)
454    movi    a3, 720
455# elif defined(CONFIG_ESPTOOLPY_FLASHFREQ_80M) && defined(CONFIG_SPIRAM_SPEED_40M)
456    movi    a3, 720
457# elif defined(CONFIG_ESPTOOLPY_FLASHFREQ_40M) && defined(CONFIG_SPIRAM_SPEED_40M)
458    movi    a3, 1200
459# elif defined(CONFIG_ESPTOOLPY_FLASHFREQ_26M) && defined(CONFIG_SPIRAM_SPEED_40M)
460    movi    a3, 1680
461# else
462    movi    a3, 2160
463# endif
464#endif
4652:  rsr.ccount  a4                          /* delay_us(N) */
466    sub     a4, a4, a2
467    bltu    a4, a3, 2b
468
469    beqz    a5, 2f
470    movi    a2, _lx_intr_livelock_app
471    l32i    a2, a2, 0
472    beqi    a2, 2, 8f
473    j       3f
474
4752:  movi    a2, _lx_intr_livelock_pro
476    l32i    a4, a2, 0
477    addi    a4, a4, 1
478    s32i    a4, a2, 0
479
480    movi    a2, _lx_intr_livelock_sync
481    movi    a3, 1
482    addx4   a3, a3, a2
483    l32i    a2, a2, 0
484    l32i    a3, a3, 0
485    and     a2, a2, a3
486    beqz    a2, 5f
487    j       1b
4885:  bgei    a4, 2, 4f
489    j       1b
490
491    /*
492    Pro cpu (Core 0) jump bypass, continue waiting, App cpu (Core 1)
493    can execute to here, unmap itself tg1 1st stage timeout interrupt
494    then restore registers and exit highint5/4.
495    */
4963:  intr_matrix_map DPORT_APP_MAC_INTR_MAP_REG, ETS_TG1_WDT_LEVEL_INTR_SOURCE, 16
497    j       9f
498
499    /*
500    Here, App cpu (Core 1) has exited isr, Pro cpu (Core 0) help the
501    App cpu map tg1 1st stage timeout interrupt clear tg1 interrupt.
502    */
5034:  intr_matrix_map DPORT_APP_MAC_INTR_MAP_REG, ETS_TG1_WDT_LEVEL_INTR_SOURCE, ETS_T1_WDT_INUM
504
5051:  movi    a2, _lx_intr_livelock_sync
506    movi    a4, 1
507    addx4   a3, a4, a2
508    l32i    a2, a2, 0
509    l32i    a3, a3, 0
510    and     a2, a2, a3
511    beqz    a2, 1b                          /* Wait for App cpu to enter highint5/4 again */
512
513    wdt_clr_intr_status TIMERG1
514    j       9f
515
516    /* Feed watchdog */
5178:  wdt_feed    TIMERG1
518
5199:  wsr     a0, PS                          /* restore interrupt level */
520
521    movi    a0, 0
522    beqz    a5, 1f
523    movi    a2, _lx_intr_livelock_app
524    l32i    a3, a2, 0
525    bnei    a3, 2, 1f
526    s32i    a0, a2, 0
527
5281:  bnez    a5, 2f
529    movi    a2, _lx_intr_livelock_pro
530    s32i    a0, a2, 0
5312:  movi    a2, _lx_intr_livelock_sync
532    addx4   a2, a5, a2
533    s32i    a0, a2, 0
534
535    /* Done. Restore registers and return. */
536    movi    a0, LX_INTR_STACK_SIZE
537    mull    a5, a5, a0
538    movi    a0, _lx_intr_stack
539    add     a0, a0, a5
540    l32i    a2, a0, LX_INTR_A2_OFFSET
541    l32i    a3, a0, LX_INTR_A3_OFFSET
542    l32i    a4, a0, LX_INTR_A4_OFFSET
543    rsync                                   /* ensure register restored */
544
545    rsr     a5, depc
546
547    rsr     a0, EXCSAVE_X                   /* restore a0 */
548    rfi     RFI_X
549
550#endif
551
552/* The linker has no reason to link in this file; all symbols it exports are already defined
553   (weakly!) in the default int handler. Define a symbol here so we can use it to have the
554   linker inspect this anyway. */
555
556    .global ld_include_highint_hdl
557ld_include_highint_hdl:
558