]> granicus.if.org Git - esp-idf/blob - components/spi_flash/flash_ops.c
512f6d20d2c1e5e6e9d98a80d04d443e3f77ea56
[esp-idf] / components / spi_flash / flash_ops.c
1 // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
2 //
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
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
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.
14
15 #include <stdlib.h>
16 #include <assert.h>
17 #include <string.h>
18 #include <stdio.h>
19
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>
25 #include <soc/soc.h>
26 #include <soc/dport_reg.h>
27 #include "sdkconfig.h"
28 #include "esp_ipc.h"
29 #include "esp_attr.h"
30 #include "esp_spi_flash.h"
31 #include "esp_log.h"
32 #include "cache_utils.h"
33
34 #if CONFIG_SPI_FLASH_ENABLE_COUNTERS
35 static const char* TAG = "spi_flash";
36 static spi_flash_counters_t s_flash_stats;
37
38 #define COUNTER_START()     uint32_t ts_begin = xthal_get_ccount()
39 #define COUNTER_STOP(counter)  \
40     do{ \
41         s_flash_stats.counter.count++; \
42         s_flash_stats.counter.time += (xthal_get_ccount() - ts_begin) / (XT_CLOCK_FREQ / 1000000); \\
43     } while(0)
44
45 #define COUNTER_ADD_BYTES(counter, size) \
46     do { \
47         s_flash_stats.counter.bytes += size; \
48     } while (0)
49
50 #else
51 #define COUNTER_START()
52 #define COUNTER_STOP(counter)
53 #define COUNTER_ADD_BYTES(counter, size)
54
55 #endif //CONFIG_SPI_FLASH_ENABLE_COUNTERS
56
57 static esp_err_t spi_flash_translate_rc(SpiFlashOpResult rc);
58
59 void spi_flash_init()
60 {
61     spi_flash_init_lock();
62 #if CONFIG_SPI_FLASH_ENABLE_COUNTERS
63     spi_flash_reset_counters();
64 #endif
65 }
66
67 size_t spi_flash_get_chip_size()
68 {
69     return g_rom_flashchip.chip_size;
70 }
71
72 SpiFlashOpResult IRAM_ATTR spi_flash_unlock()
73 {
74     static bool unlocked = false;
75     if (!unlocked) {
76         SpiFlashOpResult rc = SPIUnlock();
77         if (rc != SPI_FLASH_RESULT_OK) {
78             return rc;
79         }
80         unlocked = true;
81     }
82     return SPI_FLASH_RESULT_OK;
83 }
84
85 esp_err_t IRAM_ATTR spi_flash_erase_sector(size_t sec)
86 {
87     return spi_flash_erase_range(sec * SPI_FLASH_SEC_SIZE, SPI_FLASH_SEC_SIZE);
88 }
89
90 esp_err_t IRAM_ATTR spi_flash_erase_range(uint32_t start_addr, uint32_t size)
91 {
92     if (start_addr % SPI_FLASH_SEC_SIZE != 0) {
93         return ESP_ERR_INVALID_ARG;
94     }
95     if (size % SPI_FLASH_SEC_SIZE != 0) {
96         return ESP_ERR_INVALID_SIZE;
97     }
98     if (size + start_addr > spi_flash_get_chip_size()) {
99         return ESP_ERR_INVALID_SIZE;
100     }
101     size_t start = start_addr / SPI_FLASH_SEC_SIZE;
102     size_t end = start + size / SPI_FLASH_SEC_SIZE;
103     const size_t sectors_per_block = 16;
104     COUNTER_START();
105     spi_flash_disable_interrupts_caches_and_other_cpu();
106     SpiFlashOpResult rc;
107     rc = spi_flash_unlock();
108     if (rc == SPI_FLASH_RESULT_OK) {
109         for (size_t sector = start; sector != end && rc == SPI_FLASH_RESULT_OK; ) {
110             if (sector % sectors_per_block == 0 && end - sector > sectors_per_block) {
111                 rc = SPIEraseBlock(sector / sectors_per_block);
112                 sector += sectors_per_block;
113                 COUNTER_ADD_BYTES(erase, sectors_per_block * SPI_FLASH_SEC_SIZE);
114             }
115             else {
116                 rc = SPIEraseSector(sector);
117                 ++sector;
118                 COUNTER_ADD_BYTES(erase, SPI_FLASH_SEC_SIZE);
119             }
120         }
121     }
122     spi_flash_enable_interrupts_caches_and_other_cpu();
123     COUNTER_STOP(erase);
124     return spi_flash_translate_rc(rc);
125 }
126
127 esp_err_t IRAM_ATTR spi_flash_write(size_t dest_addr, const uint8_t *src, size_t size)
128 {
129     // TODO: replace this check with code which deals with unaligned sources
130     if (((ptrdiff_t) src) % 4 != 0) {
131         return ESP_ERR_INVALID_ARG;
132     }
133     // Destination alignment is also checked in ROM code, but we can give
134     // better error code here
135     // TODO: add handling of unaligned destinations
136     if (dest_addr % 4 != 0) {
137         return ESP_ERR_INVALID_ARG;
138     }
139     if (size % 4 != 0) {
140         return ESP_ERR_INVALID_SIZE;
141     }
142     // Out of bound writes are checked in ROM code, but we can give better
143     // error code here
144     if (dest_addr + size > g_rom_flashchip.chip_size) {
145         return ESP_ERR_INVALID_SIZE;
146     }
147     COUNTER_START();
148     spi_flash_disable_interrupts_caches_and_other_cpu();
149     SpiFlashOpResult rc;
150     rc = spi_flash_unlock();
151     if (rc == SPI_FLASH_RESULT_OK) {
152         rc = SPIWrite((uint32_t) dest_addr, (const uint32_t*) src, (int32_t) size);
153         COUNTER_ADD_BYTES(write, size);
154     }
155     spi_flash_enable_interrupts_caches_and_other_cpu();
156     COUNTER_STOP(write);
157     return spi_flash_translate_rc(rc);
158 }
159
160 esp_err_t IRAM_ATTR spi_flash_read(size_t src_addr, uint8_t *dest, size_t size)
161 {
162     // TODO: replace this check with code which deals with unaligned destinations
163     if (((ptrdiff_t) dest) % 4 != 0) {
164         return ESP_ERR_INVALID_ARG;
165     }
166     // Source alignment is also checked in ROM code, but we can give
167     // better error code here
168     // TODO: add handling of unaligned destinations
169     if (src_addr % 4 != 0) {
170         return ESP_ERR_INVALID_ARG;
171     }
172     if (size % 4 != 0) {
173         return ESP_ERR_INVALID_SIZE;
174     }
175     // Out of bound reads are checked in ROM code, but we can give better
176     // error code here
177     if (src_addr + size > g_rom_flashchip.chip_size) {
178         return ESP_ERR_INVALID_SIZE;
179     }
180     COUNTER_START();
181     spi_flash_disable_interrupts_caches_and_other_cpu();
182     SpiFlashOpResult rc = SPIRead((uint32_t) src_addr, (uint32_t*) dest, (int32_t) size);
183     COUNTER_ADD_BYTES(read, size);
184     spi_flash_enable_interrupts_caches_and_other_cpu();
185     COUNTER_STOP(read);
186     return spi_flash_translate_rc(rc);
187 }
188
189 static esp_err_t spi_flash_translate_rc(SpiFlashOpResult rc)
190 {
191     switch (rc) {
192     case SPI_FLASH_RESULT_OK:
193         return ESP_OK;
194     case SPI_FLASH_RESULT_TIMEOUT:
195         return ESP_ERR_FLASH_OP_TIMEOUT;
196     case SPI_FLASH_RESULT_ERR:
197     default:
198         return ESP_ERR_FLASH_OP_FAIL;
199     }
200 }
201
202 #if CONFIG_SPI_FLASH_ENABLE_COUNTERS
203
204 static inline void dump_counter(spi_flash_counter_t* counter, const char* name)
205 {
206     ESP_LOGI(TAG, "%s  count=%8d  time=%8dms  bytes=%8d\n", name,
207             counter->count, counter->time, counter->bytes);
208 }
209
210 const spi_flash_counters_t* spi_flash_get_counters()
211 {
212     return &s_flash_stats;
213 }
214
215 void spi_flash_reset_counters()
216 {
217     memset(&s_flash_stats, 0, sizeof(s_flash_stats));
218 }
219
220 void spi_flash_dump_counters()
221 {
222     dump_counter(&s_flash_stats.read,  "read ");
223     dump_counter(&s_flash_stats.write, "write");
224     dump_counter(&s_flash_stats.erase, "erase");
225 }
226
227 #endif //CONFIG_SPI_FLASH_ENABLE_COUNTERS