1/* 2 * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 */ 6 7 8#include <xtensa/coreasm.h> 9#include <xtensa/corebits.h> 10#include <xtensa/config/system.h> 11#include "freertos/xtensa_context.h" 12#include "sdkconfig.h" 13#include "soc/soc.h" 14 15#if CONFIG_BTDM_CTRL_HLI 16 17/* Interrupt stack size, for C code. 18 * TODO: reduce and make configurable. 19 */ 20#define L4_INTR_STACK_SIZE 4096 21 22/* Save area for the CPU state: 23 * - 64 words for the general purpose registers 24 * - 7 words for some of the special registers: 25 * - WINDOWBASE, WINDOWSTART — only WINDOWSTART is truly needed 26 * - SAR, LBEG, LEND, LCOUNT — since the C code might use these 27 * - EPC1 — since the C code might cause window overflow exceptions 28 * This is not laid out as standard exception frame structure 29 * for simplicity of the save/restore code. 30 */ 31#define REG_FILE_SIZE (64 * 4) 32#define SPECREG_OFFSET REG_FILE_SIZE 33#define SPECREG_SIZE (7 * 4) 34#define REG_SAVE_AREA_SIZE (SPECREG_OFFSET + SPECREG_SIZE) 35 36 .data 37_l4_intr_stack: 38 .space L4_INTR_STACK_SIZE 39_l4_save_ctx: 40 .space REG_SAVE_AREA_SIZE 41 42 .section .iram1,"ax" 43 .global xt_highint4 44 .type xt_highint4,@function 45 .align 4 46 47xt_highint4: 48 49#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX 50 /* 51 Here, Timer2 is used to count a little time(50us). 52 The subsequent dram0 write operation is blocked due to live lock, which will 53 cause timer2 to timeout and trigger a level 5 interrupt. 54 */ 55 rsr.ccount a0 56 addmi a0, a0, (CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ*50) 57 wsr a0, CCOMPARE2 58 59 /* Enable Timer 2 interrupt */ 60 rsr a0, INTENABLE 61 extui a0, a0, 16, 1 62 bnez a0, 1f 63 movi a0, 0 64 xsr a0, INTENABLE /* disable all interrupts */ 65 /* And a0 with (1 << 16) for Timer 2 interrupt mask */ 66 addmi a0, a0, (1<<14) 67 addmi a0, a0, (1<<14) 68 addmi a0, a0, (1<<14) 69 addmi a0, a0, (1<<14) 70 wsr a0, INTENABLE /* Enable Timer 2 */ 711: 72#endif 73 74 movi a0, _l4_save_ctx 75 /* save 4 lower registers */ 76 s32i a1, a0, 4 77 s32i a2, a0, 8 78 s32i a3, a0, 12 79 rsr a2, EXCSAVE_4 /* holds the value of a0 */ 80 s32i a2, a0, 0 81 82 /* Save special registers */ 83 addi a0, a0, SPECREG_OFFSET 84 rsr a2, WINDOWBASE 85 s32i a2, a0, 0 86 rsr a2, WINDOWSTART 87 s32i a2, a0, 4 88 rsr a2, SAR 89 s32i a2, a0, 8 90 rsr a2, LBEG 91 s32i a2, a0, 12 92 rsr a2, LEND 93 s32i a2, a0, 16 94 rsr a2, LCOUNT 95 s32i a2, a0, 20 96 rsr a2, EPC1 97 s32i a2, a0, 24 98 99#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX 100 movi a0, 0 101 xsr a0, INTENABLE /* disable all interrupts */ 102 movi a2, ~(1<<16) 103 and a0, a2, a0 104 wsr a0, INTENABLE 105#endif 106 107 /* disable exception mode, window overflow */ 108 movi a0, PS_INTLEVEL(5) | PS_EXCM 109 wsr a0, PS 110 rsync 111 112 /* Save the remaining physical registers. 113 * 4 registers are already saved, which leaves 60 registers to save. 114 * (FIXME: consider the case when the CPU is configured with physical 32 registers) 115 * These 60 registers are saved in 5 iterations, 12 registers at a time. 116 */ 117 movi a1, 5 118 movi a3, _l4_save_ctx + 4 * 4 119 120 /* This is repeated 5 times, each time the window is shifted by 12 registers. 121 * We come here with a1 = downcounter, a3 = save pointer, a2 and a0 unused. 122 */ 1231: 124 s32i a4, a3, 0 125 s32i a5, a3, 4 126 s32i a6, a3, 8 127 s32i a7, a3, 12 128 s32i a8, a3, 16 129 s32i a9, a3, 20 130 s32i a10, a3, 24 131 s32i a11, a3, 28 132 s32i a12, a3, 32 133 s32i a13, a3, 36 134 s32i a14, a3, 40 135 s32i a15, a3, 44 136 137 /* We are about to rotate the window, so that a12-a15 will become the new a0-a3. 138 * Copy a0-a3 to a12-15 to still have access to these values. 139 * At the same time we can decrement the counter and adjust the save area pointer 140 */ 141 142 /* a0 is constant (_l4_save_ctx), no need to copy */ 143 addi a13, a1, -1 /* copy and decrement the downcounter */ 144 /* a2 is scratch so no need to copy */ 145 addi a15, a3, 48 /* copy and adjust the save area pointer */ 146 beqz a13, 2f /* have saved all registers ? */ 147 rotw 3 /* rotate the window and go back */ 148 j 1b 149 150 /* the loop is complete */ 1512: 152 rotw 4 /* this brings us back to the original window */ 153 /* a0 still points to _l4_save_ctx */ 154 155 /* Can clear WINDOWSTART now, all registers are saved */ 156 rsr a2, WINDOWBASE 157 /* WINDOWSTART = (1 << WINDOWBASE) */ 158 movi a3, 1 159 ssl a2 160 sll a3, a3 161 wsr a3, WINDOWSTART 162 163_highint4_stack_switch: 164 movi a0, 0 165 movi sp, _l4_intr_stack + L4_INTR_STACK_SIZE - 16 166 s32e a0, sp, -12 /* For GDB: set null SP */ 167 s32e a0, sp, -16 /* For GDB: set null PC */ 168 movi a0, _highint4_stack_switch /* For GDB: cosmetics, for the frame where stack switch happened */ 169 170 /* Set up PS for C, disable all interrupts except NMI and debug, and clear EXCM. */ 171 movi a6, PS_INTLEVEL(4) | PS_UM | PS_WOE 172 wsr a6, PS 173 rsync 174 175 /* Call C handler */ 176 mov a6, sp 177 call4 hli_c_handler 178 179 l32e sp, sp, -12 /* switch back to the original stack */ 180 181 /* Done with C handler; re-enable exception mode, disabling window overflow */ 182 movi a2, PS_INTLEVEL(5) | PS_EXCM /* TOCHECK */ 183 wsr a2, PS 184 rsync 185 186 /* Restore the special registers. 187 * WINDOWSTART will be restored near the end. 188 */ 189 movi a0, _l4_save_ctx + SPECREG_OFFSET 190 l32i a2, a0, 8 191 wsr a2, SAR 192 l32i a2, a0, 12 193 wsr a2, LBEG 194 l32i a2, a0, 16 195 wsr a2, LEND 196 l32i a2, a0, 20 197 wsr a2, LCOUNT 198 l32i a2, a0, 24 199 wsr a2, EPC1 200 201 /* Restoring the physical registers. 202 * This is the reverse to the saving process above. 203 */ 204 205 /* Rotate back to the final window, then start loading 12 registers at a time, 206 * in 5 iterations. 207 * Again, a1 is the downcounter and a3 is the save area pointer. 208 * After each rotation, a1 and a3 are copied from a13 and a15. 209 * To simplify the loop, we put the initial values into a13 and a15. 210 */ 211 rotw -4 212 movi a15, _l4_save_ctx + 64 * 4 /* point to the end of the save area */ 213 movi a13, 5 214 2151: 216 /* Copy a1 and a3 from their previous location, 217 * at the same time decrementing and adjusting the save area pointer. 218 */ 219 addi a1, a13, -1 220 addi a3, a15, -48 221 222 /* Load 12 registers */ 223 l32i a4, a3, 0 224 l32i a5, a3, 4 225 l32i a6, a3, 8 226 l32i a7, a3, 12 227 l32i a8, a3, 16 228 l32i a9, a3, 20 229 l32i a10, a3, 24 230 l32i a11, a3, 28 /* ensure PS and EPC written */ 231 l32i a12, a3, 32 232 l32i a13, a3, 36 233 l32i a14, a3, 40 234 l32i a15, a3, 44 235 236 /* Done with the loop? */ 237 beqz a1, 2f 238 /* If no, rotate the window and repeat */ 239 rotw -3 240 j 1b 241 2422: 243 /* Done with the loop. Only 4 registers (a0-a3 in the original window) remain 244 * to be restored. Also need to restore WINDOWSTART, since all the general 245 * registers are now in place. 246 */ 247 movi a0, _l4_save_ctx 248 249 l32i a2, a0, SPECREG_OFFSET + 4 250 wsr a2, WINDOWSTART 251 252 l32i a1, a0, 4 253 l32i a2, a0, 8 254 l32i a3, a0, 12 255 rsr a0, EXCSAVE_4 /* holds the value of a0 before the interrupt handler */ 256 257 /* Return from the interrupt, restoring PS from EPS_4 */ 258 rfi 4 259 260#endif /* CONFIG_BTDM_CTRL_HLI */ 261 262/* The linker has no reason to link in this file; all symbols it exports are already defined 263 (weakly!) in the default int handler. Define a symbol here so we can use it to have the 264 linker inspect this anyway. */ 265 266 .global ld_include_hli_vectors_bt 267ld_include_hli_vectors_bt: 268