1 // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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.
20 #include <freertos/FreeRTOS.h>
21 #include <freertos/task.h>
22 #include <freertos/semphr.h>
23 #include <rom/spi_flash.h>
24 #include <rom/cache.h>
26 #include <soc/dport_reg.h>
27 #include "sdkconfig.h"
30 #include "esp_intr_alloc.h"
31 #include "esp_spi_flash.h"
35 static void IRAM_ATTR spi_flash_disable_cache(uint32_t cpuid, uint32_t* saved_state);
36 static void IRAM_ATTR spi_flash_restore_cache(uint32_t cpuid, uint32_t saved_state);
38 static uint32_t s_flash_op_cache_state[2];
40 #ifndef CONFIG_FREERTOS_UNICORE
41 static SemaphoreHandle_t s_flash_op_mutex;
42 static volatile bool s_flash_op_can_start = false;
43 static volatile bool s_flash_op_complete = false;
45 static volatile int s_flash_op_cpu = -1;
48 void spi_flash_init_lock()
50 s_flash_op_mutex = xSemaphoreCreateRecursiveMutex();
51 assert(s_flash_op_mutex != NULL);
54 void spi_flash_op_lock()
56 xSemaphoreTakeRecursive(s_flash_op_mutex, portMAX_DELAY);
59 void spi_flash_op_unlock()
61 xSemaphoreGiveRecursive(s_flash_op_mutex);
64 If you're going to modify this, keep in mind that while the flash caches of the pro and app
65 cpu are separate, the psram cache is *not*. If one of the CPUs returns from a flash routine
66 with its cache enabled but the other CPUs cache is not enabled yet, you will have problems
67 when accessing psram from the former CPU.
70 void IRAM_ATTR spi_flash_op_block_func(void* arg)
72 // Disable scheduler on this CPU
74 // Restore interrupts that aren't located in IRAM
75 esp_intr_noniram_disable();
76 uint32_t cpuid = (uint32_t) arg;
77 // s_flash_op_complete flag is cleared on *this* CPU, otherwise the other
78 // CPU may reset the flag back to false before IPC task has a chance to check it
79 // (if it is preempted by an ISR taking non-trivial amount of time)
80 s_flash_op_complete = false;
81 s_flash_op_can_start = true;
82 while (!s_flash_op_complete) {
83 // busy loop here and wait for the other CPU to finish flash operation
85 // Flash operation is complete, re-enable cache
86 spi_flash_restore_cache(cpuid, s_flash_op_cache_state[cpuid]);
87 // Restore interrupts that aren't located in IRAM
88 esp_intr_noniram_enable();
89 // Re-enable scheduler
93 void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu()
97 const uint32_t cpuid = xPortGetCoreID();
98 const uint32_t other_cpuid = (cpuid == 0) ? 1 : 0;
100 // For sanity check later: record the CPU which has started doing flash operation
101 assert(s_flash_op_cpu == -1);
102 s_flash_op_cpu = cpuid;
105 if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED) {
106 // Scheduler hasn't been started yet, it means that spi_flash API is being
107 // called from the 2nd stage bootloader or from user_start_cpu0, i.e. from
108 // PRO CPU. APP CPU is either in reset or spinning inside user_start_cpu1,
109 // which is in IRAM. So it is safe to disable cache for the other_cpuid here.
110 assert(other_cpuid == 1);
111 spi_flash_disable_cache(other_cpuid, &s_flash_op_cache_state[other_cpuid]);
113 // Temporarily raise current task priority to prevent a deadlock while
114 // waiting for IPC task to start on the other CPU
115 int old_prio = uxTaskPriorityGet(NULL);
116 vTaskPrioritySet(NULL, configMAX_PRIORITIES - 1);
117 // Signal to the spi_flash_op_block_task on the other CPU that we need it to
118 // disable cache there and block other tasks from executing.
119 s_flash_op_can_start = false;
120 esp_err_t ret = esp_ipc_call(other_cpuid, &spi_flash_op_block_func, (void*) other_cpuid);
121 assert(ret == ESP_OK);
122 while (!s_flash_op_can_start) {
123 // Busy loop and wait for spi_flash_op_block_func to disable cache
126 // Disable scheduler on the current CPU
128 // Can now set the priority back to the normal one
129 vTaskPrioritySet(NULL, old_prio);
130 // This is guaranteed to run on CPU <cpuid> because the other CPU is now
131 // occupied by highest priority task
132 assert(xPortGetCoreID() == cpuid);
134 // Kill interrupts that aren't located in IRAM
135 esp_intr_noniram_disable();
136 // This CPU executes this routine, with non-IRAM interrupts and the scheduler
137 // disabled. The other CPU is spinning in the spi_flash_op_block_func task, also
138 // with non-iram interrupts and the scheduler disabled. None of these CPUs will
139 // touch external RAM or flash this way, so we can safely disable caches.
140 spi_flash_disable_cache(cpuid, &s_flash_op_cache_state[cpuid]);
141 spi_flash_disable_cache(other_cpuid, &s_flash_op_cache_state[other_cpuid]);
144 void IRAM_ATTR spi_flash_enable_interrupts_caches_and_other_cpu()
146 const uint32_t cpuid = xPortGetCoreID();
147 const uint32_t other_cpuid = (cpuid == 0) ? 1 : 0;
149 // Sanity check: flash operation ends on the same CPU as it has started
150 assert(cpuid == s_flash_op_cpu);
151 // More sanity check: if scheduler isn't started, only CPU0 can call this.
152 assert(!(xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED && cpuid != 0));
156 // Re-enable cache on both CPUs. After this, cache (flash and external RAM) should work again.
157 spi_flash_restore_cache(cpuid, s_flash_op_cache_state[cpuid]);
158 spi_flash_restore_cache(other_cpuid, s_flash_op_cache_state[other_cpuid]);
160 if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
161 // Signal to spi_flash_op_block_task that flash operation is complete
162 s_flash_op_complete = true;
165 // Re-enable non-iram interrupts
166 esp_intr_noniram_enable();
168 // Resume tasks on the current CPU, if the scheduler has started.
169 // NOTE: enabling non-IRAM interrupts has to happen before this,
170 // because once the scheduler has started, due to preemption the
171 // current task can end up being moved to the other CPU.
172 // But esp_intr_noniram_enable has to be called on the same CPU which
173 // called esp_intr_noniram_disable
174 if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
178 spi_flash_op_unlock();
181 void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu_no_os()
183 const uint32_t cpuid = xPortGetCoreID();
184 const uint32_t other_cpuid = (cpuid == 0) ? 1 : 0;
186 // do not care about other CPU, it was halted upon entering panic handler
187 spi_flash_disable_cache(other_cpuid, &s_flash_op_cache_state[other_cpuid]);
188 // Kill interrupts that aren't located in IRAM
189 esp_intr_noniram_disable();
190 // Disable cache on this CPU as well
191 spi_flash_disable_cache(cpuid, &s_flash_op_cache_state[cpuid]);
194 void IRAM_ATTR spi_flash_enable_interrupts_caches_no_os()
196 const uint32_t cpuid = xPortGetCoreID();
198 // Re-enable cache on this CPU
199 spi_flash_restore_cache(cpuid, s_flash_op_cache_state[cpuid]);
200 // Re-enable non-iram interrupts
201 esp_intr_noniram_enable();
204 #else // CONFIG_FREERTOS_UNICORE
206 void spi_flash_init_lock()
210 void spi_flash_op_lock()
215 void spi_flash_op_unlock()
221 void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu()
224 esp_intr_noniram_disable();
225 spi_flash_disable_cache(0, &s_flash_op_cache_state[0]);
228 void IRAM_ATTR spi_flash_enable_interrupts_caches_and_other_cpu()
230 spi_flash_restore_cache(0, s_flash_op_cache_state[0]);
231 esp_intr_noniram_enable();
232 spi_flash_op_unlock();
235 void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu_no_os()
237 // Kill interrupts that aren't located in IRAM
238 esp_intr_noniram_disable();
239 // Disable cache on this CPU as well
240 spi_flash_disable_cache(0, &s_flash_op_cache_state[0]);
243 void IRAM_ATTR spi_flash_enable_interrupts_caches_no_os()
245 // Re-enable cache on this CPU
246 spi_flash_restore_cache(0, s_flash_op_cache_state[0]);
247 // Re-enable non-iram interrupts
248 esp_intr_noniram_enable();
251 #endif // CONFIG_FREERTOS_UNICORE
254 * The following two functions are replacements for Cache_Read_Disable and Cache_Read_Enable
255 * function in ROM. They are used to work around a bug where Cache_Read_Disable requires a call to
256 * Cache_Flush before Cache_Read_Enable, even if cached data was not modified.
259 static const uint32_t cache_mask = DPORT_APP_CACHE_MASK_OPSDRAM | DPORT_APP_CACHE_MASK_DROM0 |
260 DPORT_APP_CACHE_MASK_DRAM1 | DPORT_APP_CACHE_MASK_IROM0 |
261 DPORT_APP_CACHE_MASK_IRAM1 | DPORT_APP_CACHE_MASK_IRAM0;
263 static void IRAM_ATTR spi_flash_disable_cache(uint32_t cpuid, uint32_t* saved_state)
267 ret |= DPORT_GET_PERI_REG_BITS2(DPORT_PRO_CACHE_CTRL1_REG, cache_mask, 0);
268 while (DPORT_GET_PERI_REG_BITS2(DPORT_PRO_DCACHE_DBUG0_REG, DPORT_PRO_CACHE_STATE, DPORT_PRO_CACHE_STATE_S) != 1) {
271 DPORT_SET_PERI_REG_BITS(DPORT_PRO_CACHE_CTRL_REG, 1, 0, DPORT_PRO_CACHE_ENABLE_S);
273 ret |= DPORT_GET_PERI_REG_BITS2(DPORT_APP_CACHE_CTRL1_REG, cache_mask, 0);
274 while (DPORT_GET_PERI_REG_BITS2(DPORT_APP_DCACHE_DBUG0_REG, DPORT_APP_CACHE_STATE, DPORT_APP_CACHE_STATE_S) != 1) {
277 DPORT_SET_PERI_REG_BITS(DPORT_APP_CACHE_CTRL_REG, 1, 0, DPORT_APP_CACHE_ENABLE_S);
282 static void IRAM_ATTR spi_flash_restore_cache(uint32_t cpuid, uint32_t saved_state)
285 DPORT_SET_PERI_REG_BITS(DPORT_PRO_CACHE_CTRL_REG, 1, 1, DPORT_PRO_CACHE_ENABLE_S);
286 DPORT_SET_PERI_REG_BITS(DPORT_PRO_CACHE_CTRL1_REG, cache_mask, saved_state, 0);
288 DPORT_SET_PERI_REG_BITS(DPORT_APP_CACHE_CTRL_REG, 1, 1, DPORT_APP_CACHE_ENABLE_S);
289 DPORT_SET_PERI_REG_BITS(DPORT_APP_CACHE_CTRL1_REG, cache_mask, saved_state, 0);
294 IRAM_ATTR bool spi_flash_cache_enabled()
296 bool result = (DPORT_REG_GET_BIT(DPORT_PRO_CACHE_CTRL_REG, DPORT_PRO_CACHE_ENABLE) != 0);
297 #if portNUM_PROCESSORS == 2
298 result = result && (DPORT_REG_GET_BIT(DPORT_APP_CACHE_CTRL_REG, DPORT_APP_CACHE_ENABLE) != 0);