1/*
2 * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7#include <xtensa/coreasm.h>
8#include <xtensa/corebits.h>
9#include <xtensa/config/system.h>
10#include "freertos/xtensa_context.h"
11#include "esp_private/panic_reason.h"
12#include "sdkconfig.h"
13#include "soc/soc.h"
14#include "soc/dport_reg.h"
15
16/* High-priority interrupt - IPC_ISR handler */
17
18#if CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5
19#define LX_INTR_STACK_SIZE  16
20#define LX_INTR_A0_OFFSET   0
21#define LX_INTR_A2_OFFSET   4
22#define LX_INTR_A3_OFFSET   8
23#define LX_INTR_A4_OFFSET   12
24#define EXCSAVE_X           EXCSAVE_5
25#define RFI_X               5
26
27#elif CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_4
28
29#define LX_INTR_STACK_SIZE  16
30#define LX_INTR_A0_OFFSET   0
31#define LX_INTR_A2_OFFSET   4
32#define LX_INTR_A3_OFFSET   8
33#define LX_INTR_A4_OFFSET   12
34#define EXCSAVE_X           EXCSAVE_4
35#define RFI_X               4
36
37#endif /* CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5 */
38
39    .data
40_lx_intr_stack:
41    .space      LX_INTR_STACK_SIZE
42    .section .iram1,"ax"
43    .global     esp_ipc_isr_handler
44    .type       esp_ipc_isr_handler,@function
45    .align      4
46esp_ipc_isr_handler:
47    /* Allocate exception frame and save minimal context. */
48    /* Because the interrupt cause code has protection that only
49       allows one cpu to enter in the IPC_ISR section of the LX
50       interrupt at one time, there's no need to have two
51       _lx_intr_stack for each cpu */
52
53    /* Save A0, A2, A3, A4 so we can use those registers further*/
54    movi    a0, _lx_intr_stack
55    s32i    a2, a0, LX_INTR_A2_OFFSET
56    s32i    a3, a0, LX_INTR_A3_OFFSET
57    s32i    a4, a0, LX_INTR_A4_OFFSET
58    rsr     a2, EXCSAVE_X
59    s32i    a2, a0, LX_INTR_A0_OFFSET
60
61    /* disable nested iterrupts */
62    /* PS.EXCM is changed from 1 to 0 . It allows using usually exception handler instead of the Double exception handler. */
63    /* PS_UM = 1 */
64    movi    a0, PS_INTLEVEL(5) | PS_UM
65    wsr     a0, PS
66    rsync
67    /* restore PS will be done by rfi the end */
68
69    /*
70    * Reset isr interrupt flags
71    */
72#if CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5
73    /* This int is level-triggered and doesn't need clearing.
74       Do nothing here and clear int status by peripheral register later.*/
75#elif CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_4
76    /* This int is edge-triggered and needs clearing. */
77    movi    a3, (1 << ETS_IPC_ISR_INUM)
78    wsr     a3, INTCLEAR
79#endif /* CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5 */
80
81    /* get CORE_ID */
82    getcoreid   a3
83    beqz    a3, 1f
84
85    /* current cpu is 1 */
86    movi    a3, SYSTEM_CPU_INTR_FROM_CPU_3_REG
87    movi    a4, 0
88    s32i    a4, a3, 0   /* clear intr */
89    j       2f
901:
91    /* current cpu is 0 */
92    movi    a3, SYSTEM_CPU_INTR_FROM_CPU_2_REG
93    movi    a4, 0
94    s32i    a4, a3, 0   /* clear intr */
952:
96
97    /* set the start flag */
98    movi    a0, esp_ipc_isr_start_fl
99    s32i    a0, a0, 0
100
101    /* Call the esp_ipc_function(void* arg) */
102    movi    a0, esp_ipc_func
103    l32i    a0, a0, 0
104    movi    a2, esp_ipc_func_arg
105    l32i    a2, a2, 0
106    callx0  a0
107
108    /* Done. Restore registers and return. */
109    movi    a0, _lx_intr_stack
110    l32i    a2, a0, LX_INTR_A2_OFFSET
111    l32i    a3, a0, LX_INTR_A3_OFFSET
112    l32i    a4, a0, LX_INTR_A4_OFFSET
113
114    /* set the end flag */
115    movi    a0, esp_ipc_isr_end_fl
116    s32i    a0, a0, 0
117
118    /* restore a0 */
119    rsr     a0, EXCSAVE_X
120    /* restores PS from EPS[X] and jumps to the address in EPC[X] */
121    rfi     RFI_X
122