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 = xSemaphoreCreateMutex();
51 assert(s_flash_op_mutex != NULL);
54 void spi_flash_op_lock()
56 xSemaphoreTake(s_flash_op_mutex, portMAX_DELAY);
59 void spi_flash_op_unlock()
61 xSemaphoreGive(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 // Signal to the spi_flash_op_block_task on the other CPU that we need it to
114 // disable cache there and block other tasks from executing.
115 s_flash_op_can_start = false;
116 esp_err_t ret = esp_ipc_call(other_cpuid, &spi_flash_op_block_func, (void*) other_cpuid);
117 assert(ret == ESP_OK);
118 while (!s_flash_op_can_start) {
119 // Busy loop and wait for spi_flash_op_block_func to disable cache
122 // Disable scheduler on the current CPU
124 // This is guaranteed to run on CPU <cpuid> because the other CPU is now
125 // occupied by highest priority task
126 assert(xPortGetCoreID() == cpuid);
128 // Kill interrupts that aren't located in IRAM
129 esp_intr_noniram_disable();
130 // This CPU executes this routine, with non-IRAM interrupts and the scheduler
131 // disabled. The other CPU is spinning in the spi_flash_op_block_func task, also
132 // with non-iram interrupts and the scheduler disabled. None of these CPUs will
133 // touch external RAM or flash this way, so we can safely disable caches.
134 spi_flash_disable_cache(cpuid, &s_flash_op_cache_state[cpuid]);
135 spi_flash_disable_cache(other_cpuid, &s_flash_op_cache_state[other_cpuid]);
138 void IRAM_ATTR spi_flash_enable_interrupts_caches_and_other_cpu()
140 const uint32_t cpuid = xPortGetCoreID();
141 const uint32_t other_cpuid = (cpuid == 0) ? 1 : 0;
143 // Sanity check: flash operation ends on the same CPU as it has started
144 assert(cpuid == s_flash_op_cpu);
145 // More sanity check: if scheduler isn't started, only CPU0 can call this.
146 assert(!(xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED && cpuid != 0));
150 // Re-enable cache on both CPUs. After this, cache (flash and external RAM) should work again.
151 spi_flash_restore_cache(cpuid, s_flash_op_cache_state[cpuid]);
152 spi_flash_restore_cache(other_cpuid, s_flash_op_cache_state[other_cpuid]);
154 if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
155 // Signal to spi_flash_op_block_task that flash operation is complete
156 s_flash_op_complete = true;
159 // Re-enable non-iram interrupts
160 esp_intr_noniram_enable();
162 // Resume tasks on the current CPU, if the scheduler has started.
163 // NOTE: enabling non-IRAM interrupts has to happen before this,
164 // because once the scheduler has started, due to preemption the
165 // current task can end up being moved to the other CPU.
166 // But esp_intr_noniram_enable has to be called on the same CPU which
167 // called esp_intr_noniram_disable
168 if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
172 spi_flash_op_unlock();
175 void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu_no_os()
177 const uint32_t cpuid = xPortGetCoreID();
178 const uint32_t other_cpuid = (cpuid == 0) ? 1 : 0;
180 // do not care about other CPU, it was halted upon entering panic handler
181 spi_flash_disable_cache(other_cpuid, &s_flash_op_cache_state[other_cpuid]);
182 // Kill interrupts that aren't located in IRAM
183 esp_intr_noniram_disable();
184 // Disable cache on this CPU as well
185 spi_flash_disable_cache(cpuid, &s_flash_op_cache_state[cpuid]);
188 void IRAM_ATTR spi_flash_enable_interrupts_caches_no_os()
190 const uint32_t cpuid = xPortGetCoreID();
192 // Re-enable cache on this CPU
193 spi_flash_restore_cache(cpuid, s_flash_op_cache_state[cpuid]);
194 // Re-enable non-iram interrupts
195 esp_intr_noniram_enable();
198 #else // CONFIG_FREERTOS_UNICORE
200 void spi_flash_init_lock()
204 void spi_flash_op_lock()
209 void spi_flash_op_unlock()
215 void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu()
218 esp_intr_noniram_disable();
219 spi_flash_disable_cache(0, &s_flash_op_cache_state[0]);
222 void IRAM_ATTR spi_flash_enable_interrupts_caches_and_other_cpu()
224 spi_flash_restore_cache(0, s_flash_op_cache_state[0]);
225 esp_intr_noniram_enable();
226 spi_flash_op_unlock();
229 void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu_no_os()
231 // Kill interrupts that aren't located in IRAM
232 esp_intr_noniram_disable();
233 // Disable cache on this CPU as well
234 spi_flash_disable_cache(0, &s_flash_op_cache_state[0]);
237 void IRAM_ATTR spi_flash_enable_interrupts_caches_no_os()
239 // Re-enable cache on this CPU
240 spi_flash_restore_cache(0, s_flash_op_cache_state[0]);
241 // Re-enable non-iram interrupts
242 esp_intr_noniram_enable();
245 #endif // CONFIG_FREERTOS_UNICORE
248 * The following two functions are replacements for Cache_Read_Disable and Cache_Read_Enable
249 * function in ROM. They are used to work around a bug where Cache_Read_Disable requires a call to
250 * Cache_Flush before Cache_Read_Enable, even if cached data was not modified.
253 static const uint32_t cache_mask = DPORT_APP_CACHE_MASK_OPSDRAM | DPORT_APP_CACHE_MASK_DROM0 |
254 DPORT_APP_CACHE_MASK_DRAM1 | DPORT_APP_CACHE_MASK_IROM0 |
255 DPORT_APP_CACHE_MASK_IRAM1 | DPORT_APP_CACHE_MASK_IRAM0;
257 static void IRAM_ATTR spi_flash_disable_cache(uint32_t cpuid, uint32_t* saved_state)
261 ret |= DPORT_GET_PERI_REG_BITS2(DPORT_PRO_CACHE_CTRL1_REG, cache_mask, 0);
262 while (DPORT_GET_PERI_REG_BITS2(DPORT_PRO_DCACHE_DBUG0_REG, DPORT_PRO_CACHE_STATE, DPORT_PRO_CACHE_STATE_S) != 1) {
265 DPORT_SET_PERI_REG_BITS(DPORT_PRO_CACHE_CTRL_REG, 1, 0, DPORT_PRO_CACHE_ENABLE_S);
267 ret |= DPORT_GET_PERI_REG_BITS2(DPORT_APP_CACHE_CTRL1_REG, cache_mask, 0);
268 while (DPORT_GET_PERI_REG_BITS2(DPORT_APP_DCACHE_DBUG0_REG, DPORT_APP_CACHE_STATE, DPORT_APP_CACHE_STATE_S) != 1) {
271 DPORT_SET_PERI_REG_BITS(DPORT_APP_CACHE_CTRL_REG, 1, 0, DPORT_APP_CACHE_ENABLE_S);
276 static void IRAM_ATTR spi_flash_restore_cache(uint32_t cpuid, uint32_t saved_state)
279 DPORT_SET_PERI_REG_BITS(DPORT_PRO_CACHE_CTRL_REG, 1, 1, DPORT_PRO_CACHE_ENABLE_S);
280 DPORT_SET_PERI_REG_BITS(DPORT_PRO_CACHE_CTRL1_REG, cache_mask, saved_state, 0);
282 DPORT_SET_PERI_REG_BITS(DPORT_APP_CACHE_CTRL_REG, 1, 1, DPORT_APP_CACHE_ENABLE_S);
283 DPORT_SET_PERI_REG_BITS(DPORT_APP_CACHE_CTRL1_REG, cache_mask, saved_state, 0);
288 IRAM_ATTR bool spi_flash_cache_enabled()
290 return DPORT_REG_GET_BIT(DPORT_PRO_CACHE_CTRL_REG, DPORT_PRO_CACHE_ENABLE)
291 && DPORT_REG_GET_BIT(DPORT_APP_CACHE_CTRL_REG, DPORT_APP_CACHE_ENABLE);