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();
53 void spi_flash_op_lock()
55 xSemaphoreTake(s_flash_op_mutex, portMAX_DELAY);
58 void spi_flash_op_unlock()
60 xSemaphoreGive(s_flash_op_mutex);
63 void IRAM_ATTR spi_flash_op_block_func(void* arg)
65 // Disable scheduler on this CPU
67 // Restore interrupts that aren't located in IRAM
68 esp_intr_noniram_disable();
69 uint32_t cpuid = (uint32_t) arg;
70 // Disable cache so that flash operation can start
71 spi_flash_disable_cache(cpuid, &s_flash_op_cache_state[cpuid]);
72 // s_flash_op_complete flag is cleared on *this* CPU, otherwise the other
73 // CPU may reset the flag back to false before IPC task has a chance to check it
74 // (if it is preempted by an ISR taking non-trivial amount of time)
75 s_flash_op_complete = false;
76 s_flash_op_can_start = true;
77 while (!s_flash_op_complete) {
78 // busy loop here and wait for the other CPU to finish flash operation
80 // Flash operation is complete, re-enable cache
81 spi_flash_restore_cache(cpuid, s_flash_op_cache_state[cpuid]);
82 // Restore interrupts that aren't located in IRAM
83 esp_intr_noniram_enable();
84 // Re-enable scheduler
88 void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu()
92 const uint32_t cpuid = xPortGetCoreID();
93 const uint32_t other_cpuid = (cpuid == 0) ? 1 : 0;
95 // For sanity check later: record the CPU which has started doing flash operation
96 assert(s_flash_op_cpu == -1);
97 s_flash_op_cpu = cpuid;
100 if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED) {
101 // Scheduler hasn't been started yet, it means that spi_flash API is being
102 // called from the 2nd stage bootloader or from user_start_cpu0, i.e. from
103 // PRO CPU. APP CPU is either in reset or spinning inside user_start_cpu1,
104 // which is in IRAM. So it is safe to disable cache for the other_cpuid here.
105 assert(other_cpuid == 1);
106 spi_flash_disable_cache(other_cpuid, &s_flash_op_cache_state[other_cpuid]);
108 // Signal to the spi_flash_op_block_task on the other CPU that we need it to
109 // disable cache there and block other tasks from executing.
110 s_flash_op_can_start = false;
111 esp_err_t ret = esp_ipc_call(other_cpuid, &spi_flash_op_block_func, (void*) other_cpuid);
112 assert(ret == ESP_OK);
113 while (!s_flash_op_can_start) {
114 // Busy loop and wait for spi_flash_op_block_func to disable cache
117 // Disable scheduler on the current CPU
119 // This is guaranteed to run on CPU <cpuid> because the other CPU is now
120 // occupied by highest priority task
121 assert(xPortGetCoreID() == cpuid);
123 // Kill interrupts that aren't located in IRAM
124 esp_intr_noniram_disable();
125 // Disable cache on this CPU as well
126 spi_flash_disable_cache(cpuid, &s_flash_op_cache_state[cpuid]);
129 void IRAM_ATTR spi_flash_enable_interrupts_caches_and_other_cpu()
131 const uint32_t cpuid = xPortGetCoreID();
132 const uint32_t other_cpuid = (cpuid == 0) ? 1 : 0;
134 // Sanity check: flash operation ends on the same CPU as it has started
135 assert(cpuid == s_flash_op_cpu);
139 // Re-enable cache on this CPU
140 spi_flash_restore_cache(cpuid, s_flash_op_cache_state[cpuid]);
142 if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED) {
143 // Scheduler is not running yet — this means we are running on PRO CPU.
144 // other_cpuid is APP CPU, and it is either in reset or is spinning in
145 // user_start_cpu1, which is in IRAM. So we can simply reenable cache.
146 assert(other_cpuid == 1);
147 spi_flash_restore_cache(other_cpuid, s_flash_op_cache_state[other_cpuid]);
149 // Signal to spi_flash_op_block_task that flash operation is complete
150 s_flash_op_complete = true;
152 // Re-enable non-iram interrupts
153 esp_intr_noniram_enable();
155 // Resume tasks on the current CPU, if the scheduler has started.
156 // NOTE: enabling non-IRAM interrupts has to happen before this,
157 // because once the scheduler has started, due to preemption the
158 // current task can end up being moved to the other CPU.
159 // But esp_intr_noniram_enable has to be called on the same CPU which
160 // called esp_intr_noniram_disable
161 if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
165 spi_flash_op_unlock();
168 void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu_no_os()
170 const uint32_t cpuid = xPortGetCoreID();
171 const uint32_t other_cpuid = (cpuid == 0) ? 1 : 0;
173 // do not care about other CPU, it was halted upon entering panic handler
174 spi_flash_disable_cache(other_cpuid, &s_flash_op_cache_state[other_cpuid]);
175 // Kill interrupts that aren't located in IRAM
176 esp_intr_noniram_disable();
177 // Disable cache on this CPU as well
178 spi_flash_disable_cache(cpuid, &s_flash_op_cache_state[cpuid]);
181 void IRAM_ATTR spi_flash_enable_interrupts_caches_no_os()
183 const uint32_t cpuid = xPortGetCoreID();
185 // Re-enable cache on this CPU
186 spi_flash_restore_cache(cpuid, s_flash_op_cache_state[cpuid]);
187 // Re-enable non-iram interrupts
188 esp_intr_noniram_enable();
191 #else // CONFIG_FREERTOS_UNICORE
193 void spi_flash_init_lock()
197 void spi_flash_op_lock()
202 void spi_flash_op_unlock()
208 void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu()
211 esp_intr_noniram_disable();
212 spi_flash_disable_cache(0, &s_flash_op_cache_state[0]);
215 void IRAM_ATTR spi_flash_enable_interrupts_caches_and_other_cpu()
217 spi_flash_restore_cache(0, s_flash_op_cache_state[0]);
218 esp_intr_noniram_enable();
219 spi_flash_op_unlock();
222 void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu_no_os()
224 // Kill interrupts that aren't located in IRAM
225 esp_intr_noniram_disable();
226 // Disable cache on this CPU as well
227 spi_flash_disable_cache(0, &s_flash_op_cache_state[0]);
230 void IRAM_ATTR spi_flash_enable_interrupts_caches_no_os()
232 // Re-enable cache on this CPU
233 spi_flash_restore_cache(0, s_flash_op_cache_state[0]);
234 // Re-enable non-iram interrupts
235 esp_intr_noniram_enable();
238 #endif // CONFIG_FREERTOS_UNICORE
241 * The following two functions are replacements for Cache_Read_Disable and Cache_Read_Enable
242 * function in ROM. They are used to work around a bug where Cache_Read_Disable requires a call to
243 * Cache_Flush before Cache_Read_Enable, even if cached data was not modified.
246 static const uint32_t cache_mask = DPORT_APP_CACHE_MASK_OPSDRAM | DPORT_APP_CACHE_MASK_DROM0 |
247 DPORT_APP_CACHE_MASK_DRAM1 | DPORT_APP_CACHE_MASK_IROM0 |
248 DPORT_APP_CACHE_MASK_IRAM1 | DPORT_APP_CACHE_MASK_IRAM0;
250 static void IRAM_ATTR spi_flash_disable_cache(uint32_t cpuid, uint32_t* saved_state)
254 ret |= DPORT_GET_PERI_REG_BITS2(DPORT_PRO_CACHE_CTRL1_REG, cache_mask, 0);
255 while (DPORT_GET_PERI_REG_BITS2(DPORT_PRO_DCACHE_DBUG0_REG, DPORT_PRO_CACHE_STATE, DPORT_PRO_CACHE_STATE_S) != 1) {
258 DPORT_SET_PERI_REG_BITS(DPORT_PRO_CACHE_CTRL_REG, 1, 0, DPORT_PRO_CACHE_ENABLE_S);
260 ret |= DPORT_GET_PERI_REG_BITS2(DPORT_APP_CACHE_CTRL1_REG, cache_mask, 0);
261 while (DPORT_GET_PERI_REG_BITS2(DPORT_APP_DCACHE_DBUG0_REG, DPORT_APP_CACHE_STATE, DPORT_APP_CACHE_STATE_S) != 1) {
264 DPORT_SET_PERI_REG_BITS(DPORT_APP_CACHE_CTRL_REG, 1, 0, DPORT_APP_CACHE_ENABLE_S);
269 static void IRAM_ATTR spi_flash_restore_cache(uint32_t cpuid, uint32_t saved_state)
272 DPORT_SET_PERI_REG_BITS(DPORT_PRO_CACHE_CTRL_REG, 1, 1, DPORT_PRO_CACHE_ENABLE_S);
273 DPORT_SET_PERI_REG_BITS(DPORT_PRO_CACHE_CTRL1_REG, cache_mask, saved_state, 0);
275 DPORT_SET_PERI_REG_BITS(DPORT_APP_CACHE_CTRL_REG, 1, 1, DPORT_APP_CACHE_ENABLE_S);
276 DPORT_SET_PERI_REG_BITS(DPORT_APP_CACHE_CTRL1_REG, cache_mask, saved_state, 0);
281 IRAM_ATTR bool spi_flash_cache_enabled()
283 return DPORT_REG_GET_BIT(DPORT_PRO_CACHE_CTRL_REG, DPORT_PRO_CACHE_ENABLE)
284 && DPORT_REG_GET_BIT(DPORT_APP_CACHE_CTRL_REG, DPORT_APP_CACHE_ENABLE);