1
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
50
60
61
65
71
72
73
74
75
76
77
82
83
87
88
89
90
94
95
99
100
108
109
110
114
115
119
120
124
125
126
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
155
156
157
163
164
165
174
175
177
178
179
184
185
186
187
193
194
195
196
197
199
210
211
212
213
214
215
218
219
222
223
224
225
243
244
245
246
247
248
249
254
255
256
257
258
259
260
261
262
263
264
267
268
269
270
271
274
275
278
279
280
287
288
289
290
291
295
296
305
306
307
308
311
312
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
340
341
342
343
344
345
354
355
358
359
360
367
368
369
370
371
375
376
385
386
387
388
391
392
400
401
402
403
404
405
406
407
408
411
412
413
414
422
423
424
425
426
434
435
436
437
438
439
440
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
463
464
465
466
467
468
469
470
471
472
475
484
485
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
509
510
513
514
515
516
517
520
521
524
525
526
527
528
529
530
531
534
535
538
539
540
543
544
545
552
553
554
555
556
557
558
559
560
561
562
563
566
569
573
574
575
576
577
578
579
580
581
582
583
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
606
609
613
616
617
618
619
620
621
622
623
626
627
628
637
638
639
640
643
644
645
646
647
648
649
650
656
657
658
661
662
663
664
665
671
672
673
674
675
676
677
678
679
680
681
682
689
690
691
694
695
696
697
698
699
700
701
702
703
704
705
721
722
723
724
725
726
727
728
731
732
733
736
737
738
739
740
741
742
743
744
745
746
747
748
749
752
753
754
755
756
757
758
759
760
763
764
765
766
769
770
771
772
773
774
775
776
777
780
781
787
788
789
790
791
792
793
794
795
796
799
800
801
802
805
806
807
808
811
812
813
816
817
818
819
820
821
822
823
824
825
826
827
830
831
832
833
836
837
838
846
847
848
849
850
851
852
853
854
857
860
861
862
863
864
865
866
867
868
869
870
871
872
873
883
884
885
886
887
888
889
892
893
894
895
896
897
898
901
905
906
907
908
909
912
913
914
915
916
917
918
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
941
942
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
980
984
985
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1009
1010
1011
1012
1013
1014
1017
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1038
1039
1040
1041
1042
1043
1044
1052
1053
1054
1060
1061
1062
1065
1066
1067
1068
1074
1075
1076
1077
1078
1079
1080
1085
1086
1087
1093
1094
1095
1099
1100
1101
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1121
1122
1123
1124
1125
1131
1132
1133
1134
1135
1136
1139
1142
1145
1146
1147
1148
1149
1150
1151
1152
1153
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1175
1176
1177
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1193
1194
1195
1196
1197
1198
1199
1200
1201
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1222
1223
1224
1225
1226
1227
1230
1231
1232
1235
1236
1240
1241
1244
1245
1249
1250
1251
1252
1253
1254
1255
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1290
1291
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1325
1326
1327
1328
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1361
1362
1363
1367
1376
1377
1378
1379
1380
1386
1387
1388
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1412
1413
1414
1415
1416
1417
1418
1419
1432
1433
/* ... */
#include <stdlib.h>
#include <stdio.h>
#include <sys/param.h>
#include <string.h>
#include "esp_memory_utils.h"
#include "spi_flash_chip_driver.h"
#include "memspi_host_driver.h"
#include "esp_log.h"
#include "sdkconfig.h"
#include "esp_flash_internal.h"
#include "spi_flash_defs.h"
#include "spi_flash_mmap.h"
#include "esp_rom_caps.h"
#include "esp_rom_spiflash.h"
#include "esp_private/esp_clk.h"
#include "esp_spi_flash_counters.h"16 includes
#if CONFIG_IDF_TARGET_ESP32S2
#include "esp_crypto_lock.h"
#endif
DRAM_ATTR static const char TAG[] = "spi_flash";
#ifdef CONFIG_SPI_FLASH_WRITE_CHUNK_SIZE
#define MAX_WRITE_CHUNK CONFIG_SPI_FLASH_WRITE_CHUNK_SIZE
#else
#define MAX_WRITE_CHUNK 8192
#endif
#define MAX_READ_CHUNK 16384
#define VERIFY_BUF_LEN 64
#ifdef CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS
#define UNSAFE_WRITE_ADDRESS abort()
#else
#define UNSAFE_WRITE_ADDRESS return ESP_ERR_INVALID_ARG
#endif
/* ... */
#define CHECK_WRITE_ADDRESS(CHIP, ADDR, SIZE) do { \
if (CHIP && CHIP->os_func->region_protected) { \
esp_err_t ret = CHIP->os_func->region_protected(CHIP->os_func_data, ADDR, SIZE); \
if (ret == ESP_ERR_NOT_ALLOWED) { \
return ret; \
}{...} else if (ret != ESP_OK) { \
UNSAFE_WRITE_ADDRESS; \
}{...} \
}{...} \
}{...} while(0)...
/* ... */
#define VERIFY_CHIP_OP(op) do { \
if (err != ESP_OK) return err; \
if (chip->chip_drv->op == NULL) { \
return ESP_ERR_FLASH_UNSUPPORTED_CHIP; \
}{...} \
}{...} while (0)...
#if CONFIG_SPI_FLASH_ENABLE_COUNTERS
static esp_flash_counters_t esp_flash_stats;
#define COUNTER_START() uint32_t ts_begin = esp_cpu_get_cycle_count()
#define COUNTER_STOP(counter) \
do{ \
esp_flash_stats.counter.count++; \
esp_flash_stats.counter.time += (esp_cpu_get_cycle_count() - ts_begin) / (esp_clk_cpu_freq() / 1000000); \
}{...} while(0)...
#define COUNTER_ADD_BYTES(counter, size) \
do { \
esp_flash_stats.counter.bytes += size; \
}{...} while (0)...
const esp_flash_counters_t *esp_flash_get_counters(void)
{
return &esp_flash_stats;
}{...}
void esp_flash_reset_counters(void)
{
memset(&esp_flash_stats, 0, sizeof(esp_flash_stats));
}{...}
void esp_flash_dump_counters(FILE* stream)
{
if (stream != NULL) {
fprintf(stream, " read: count=%8ld time=%8ldus bytes=%8ld\n", esp_flash_stats.read.count, esp_flash_stats.read.time, esp_flash_stats.read.bytes);
fprintf(stream, "write: count=%8ld time=%8ldus bytes=%8ld\n", esp_flash_stats.write.count, esp_flash_stats.write.time, esp_flash_stats.write.bytes);
fprintf(stream, "erase: count=%8ld time=%8ldus bytes=%8ld\n", esp_flash_stats.erase.count, esp_flash_stats.erase.time, esp_flash_stats.erase.bytes);
}{...}
}{...}
const spi_flash_counters_t *spi_flash_get_counters(void)
{
return (spi_flash_counters_t *)esp_flash_get_counters();
}{...}
void spi_flash_reset_counters(void)
{
esp_flash_reset_counters();
}{...}
void spi_flash_dump_counters(void)
{
esp_flash_dump_counters(stdout);
}{...}
/* ... */
#else
#define COUNTER_START()
#define COUNTER_STOP(counter)
#define COUNTER_ADD_BYTES(counter, size)
/* ... */
#endif
#define IO_STR_LEN 10
static const char io_mode_str[][IO_STR_LEN] = {
"slowrd",
"fastrd",
"dout",
"dio",
"qout",
"qio",
[6 ... 15] = "not used",
"opi_str",
"opi_dtr",
}{...};
_Static_assert(sizeof(io_mode_str)/IO_STR_LEN == SPI_FLASH_READ_MODE_MAX, "the io_mode_str should be consistent with the esp_flash_io_mode_t defined in spi_flash_types.h");
esp_err_t esp_flash_read_chip_id(esp_flash_t* chip, uint32_t* flash_id);
#if !CONFIG_SPI_FLASH_ROM_IMPL || ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV
static esp_err_t spiflash_start_default(esp_flash_t *chip);
static esp_err_t spiflash_end_default(esp_flash_t *chip, esp_err_t err);
static esp_err_t check_chip_pointer_default(esp_flash_t **inout_chip);
static esp_err_t flash_end_flush_cache(esp_flash_t* chip, esp_err_t err, bool bus_acquired, uint32_t address, uint32_t length);/* ... */
#endif
typedef struct {
esp_err_t (*start)(esp_flash_t *chip);
esp_err_t (*end)(esp_flash_t *chip, esp_err_t err);
esp_err_t (*chip_check)(esp_flash_t **inout_chip);
esp_err_t (*flash_end_flush_cache)(esp_flash_t* chip, esp_err_t err, bool bus_acquired, uint32_t address, uint32_t length);
}{...} rom_spiflash_api_func_t;
#if !CONFIG_SPI_FLASH_ROM_IMPL || ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV
DRAM_ATTR static rom_spiflash_api_func_t default_spiflash_rom_api = {
.start = spiflash_start_default,
.end = spiflash_end_default,
.chip_check = check_chip_pointer_default,
.flash_end_flush_cache = flash_end_flush_cache,
}{...};
DRAM_ATTR rom_spiflash_api_func_t *rom_spiflash_api_funcs = &default_spiflash_rom_api;/* ... */
#else
extern rom_spiflash_api_func_t *esp_flash_api_funcs;
#define rom_spiflash_api_funcs esp_flash_api_funcs/* ... */
#endif
/* ... */
#if !CONFIG_SPI_FLASH_ROM_IMPL || ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV
static esp_err_t IRAM_ATTR spiflash_start_default(esp_flash_t *chip)
{
if (chip->os_func != NULL && chip->os_func->start != NULL) {
esp_err_t err = chip->os_func->start(chip->os_func_data);
if (err != ESP_OK) {
return err;
}{...}
}{...}
chip->host->driver->dev_config(chip->host);
return ESP_OK;
}{...}
/* ... */
static esp_err_t IRAM_ATTR spiflash_end_default(esp_flash_t *chip, esp_err_t err)
{
if (chip->os_func != NULL
&& chip->os_func->end != NULL) {
esp_err_t end_err = chip->os_func->end(chip->os_func_data);
if (err == ESP_OK) {
err = end_err;
}{...}
}{...}
return err;
}{...}
static IRAM_ATTR esp_err_t check_chip_pointer_default(esp_flash_t **inout_chip)
{
esp_flash_t *chip = *inout_chip;
if (chip == NULL) {
chip = esp_flash_default_chip;
}{...}
*inout_chip = chip;
if (chip == NULL || !esp_flash_chip_driver_initialized(chip)) {
return ESP_ERR_FLASH_NOT_INITIALISED;
}{...}
return ESP_OK;
}{...}
static IRAM_ATTR esp_err_t flash_end_flush_cache(esp_flash_t* chip, esp_err_t err, bool bus_acquired, uint32_t address, uint32_t length)
{
if (!bus_acquired) {
esp_err_t acquire_err = rom_spiflash_api_funcs->start(chip);
if (acquire_err != ESP_OK) {
return (err == ESP_OK)? acquire_err: err;
}{...}
}{...}
if (chip->host->driver->flush_cache) {
esp_err_t flush_err = chip->host->driver->flush_cache(chip->host, address, length);
if (err == ESP_OK) {
err = flush_err;
}{...}
}{...}
return rom_spiflash_api_funcs->end(chip, err);
}{...}
/* ... */#endif
static esp_err_t detect_spi_flash_chip(esp_flash_t *chip);
bool IRAM_ATTR esp_flash_chip_driver_initialized(const esp_flash_t *chip)
{
if (!chip->chip_drv) return false;
return true;
}{...}
esp_err_t IRAM_ATTR esp_flash_init(esp_flash_t *chip)
{
esp_err_t err = ESP_OK;
if (chip == NULL || chip->host == NULL || chip->host->driver == NULL ||
((memspi_host_inst_t*)chip->host)->spi == NULL) {
return ESP_ERR_INVALID_ARG;
}{...}
uint32_t flash_id;
int retries = 10;
do {
err = esp_flash_read_chip_id(chip, &flash_id);
}{...} while (err == ESP_ERR_FLASH_NOT_INITIALISED && retries-- > 0);
if (err != ESP_OK) {
return err;
}{...}
chip->chip_id = flash_id;
if (!esp_flash_chip_driver_initialized(chip)) {
err = detect_spi_flash_chip(chip);
if (err != ESP_OK) {
return err;
}{...}
}{...}
uint32_t size;
err = esp_flash_get_physical_size(chip, &size);
if (err != ESP_OK) {
ESP_LOGE(TAG, "failed to get chip size");
return err;
}{...}
if (chip->chip_drv->get_chip_caps == NULL) {
ESP_EARLY_LOGW(TAG, "get_chip_caps function pointer hasn't been initialized");
}{...} else {
if (((chip->chip_drv->get_chip_caps(chip) & SPI_FLASH_CHIP_CAP_32MB_SUPPORT) == 0) && (size > (16 *1024 * 1024))) {
ESP_EARLY_LOGW(TAG, "Detected flash size > 16 MB, but access beyond 16 MB is not supported for this flash model yet.");
size = (16 * 1024 * 1024);
}{...}
}{...}
ESP_LOGI(TAG, "flash io: %s", io_mode_str[chip->read_mode]);
err = rom_spiflash_api_funcs->start(chip);
if (err != ESP_OK) {
return err;
}{...}
if (err == ESP_OK) {
err = chip->chip_drv->set_io_mode(chip);
if (err == ESP_ERR_FLASH_NO_RESPONSE && !esp_flash_is_quad_mode(chip)) {
err = ESP_OK;
}{...}
}{...}
return rom_spiflash_api_funcs->end(chip, err);
}{...}
esp_err_t IRAM_ATTR esp_flash_init_main(esp_flash_t *chip)
{
esp_err_t err = ESP_OK;
bool octal_mode;
if (chip == NULL || chip->host == NULL || chip->host->driver == NULL ||
((memspi_host_inst_t*)chip->host)->spi == NULL) {
return ESP_ERR_INVALID_ARG;
}{...}
octal_mode = (chip->read_mode >= SPI_FLASH_OPI_FLAG);
uint32_t flash_id = 0;
if (octal_mode) {
flash_id = g_rom_flashchip.device_id;
}{...} else {
int retries = 10;
do {
err = esp_flash_read_chip_id(chip, &flash_id);
}{...} while (err == ESP_ERR_FLASH_NOT_INITIALISED && retries-- > 0);
}{...}
if (err != ESP_OK) {
return err;
}{...}
chip->chip_id = flash_id;
if (!esp_flash_chip_driver_initialized(chip)) {
err = detect_spi_flash_chip(chip);
if (err != ESP_OK) {
return err;
}{...}
}{...}
uint32_t size;
err = esp_flash_get_physical_size(chip, &size);
if (err != ESP_OK) {
ESP_EARLY_LOGE(TAG, "failed to get chip size");
return err;
}{...}
if (chip->chip_drv->get_chip_caps == NULL) {
ESP_EARLY_LOGW(TAG, "get_chip_caps function pointer hasn't been initialized");
}{...} else {
if (((chip->chip_drv->get_chip_caps(chip) & SPI_FLASH_CHIP_CAP_32MB_SUPPORT) == 0) && (size > (16 *1024 * 1024))) {
ESP_EARLY_LOGW(TAG, "Detected flash size > 16 MB, but access beyond 16 MB is not supported for this flash model yet.");
size = (16 * 1024 * 1024);
}{...}
}{...}
ESP_EARLY_LOGI(TAG, "flash io: %s", io_mode_str[chip->read_mode]);
err = rom_spiflash_api_funcs->start(chip);
if (err != ESP_OK) {
return err;
}{...}
if (err == ESP_OK && !octal_mode) {
err = chip->chip_drv->set_io_mode(chip);
if (err == ESP_ERR_FLASH_NO_RESPONSE && !esp_flash_is_quad_mode(chip)) {
err = ESP_OK;
}{...}
}{...}
return rom_spiflash_api_funcs->end(chip, err);
}{...}
static esp_err_t IRAM_ATTR read_id_core(esp_flash_t* chip, uint32_t* out_id, bool sanity_check)
{
bool installed = esp_flash_chip_driver_initialized(chip);
esp_err_t err = rom_spiflash_api_funcs->start(chip);
if (err != ESP_OK) {
return err;
}{...}
esp_err_t (*read_id_func)(void*, uint32_t*);
void* read_id_arg;
if (installed && chip->chip_drv->read_id) {
read_id_func = (void*)chip->chip_drv->read_id;
read_id_arg = (void*)chip;
}{...} else {
read_id_func = (void*)chip->host->driver->read_id;
read_id_arg = (void*)chip->host;
}{...}
err = read_id_func(read_id_arg, out_id);
if (sanity_check && err == ESP_OK) {
uint32_t new_id;
err = read_id_func(read_id_arg, &new_id);
if (err == ESP_OK && (new_id != *out_id)) {
err = ESP_ERR_FLASH_NOT_INITIALISED;
}{...}
}{...}
return rom_spiflash_api_funcs->end(chip, err);
}{...}
esp_err_t esp_flash_read_chip_id(esp_flash_t* chip, uint32_t* out_id)
{
return read_id_core(chip, out_id, true);
}{...}
#ifndef CONFIG_SPI_FLASH_ROM_IMPL
esp_err_t esp_flash_read_id(esp_flash_t* chip, uint32_t* out_id)
{
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
if (err != ESP_OK && !(err == ESP_ERR_FLASH_NOT_INITIALISED && chip != NULL)) return err;
if (out_id == NULL) return ESP_ERR_INVALID_ARG;
return read_id_core(chip, out_id, false);
}{...}
/* ... */#endif
static esp_err_t IRAM_ATTR NOINLINE_ATTR read_unique_id(esp_flash_t* chip, uint64_t* out_uid)
{
esp_err_t err = rom_spiflash_api_funcs->start(chip);
if (err != ESP_OK) {
return err;
}{...}
err = chip->chip_drv->read_unique_id(chip, out_uid);
return rom_spiflash_api_funcs->end(chip, err);
}{...}
esp_err_t esp_flash_read_unique_chip_id(esp_flash_t *chip, uint64_t* out_uid)
{
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
if (err != ESP_OK) {
return err;
}{...}
if (chip->chip_drv->get_chip_caps == NULL) {
ESP_EARLY_LOGW(TAG, "get_chip_caps function pointer hasn't been initialized");
}{...} else {
if ((chip->chip_drv->get_chip_caps(chip) & SPI_FLASH_CHIP_CAP_UNIQUE_ID) == 0) {
ESP_EARLY_LOGE(TAG, "chip %s doesn't support reading unique id", chip->chip_drv->name);
return ESP_ERR_NOT_SUPPORTED;
}{...}
}{...}
if (out_uid == NULL) {
return ESP_ERR_INVALID_ARG;
}{...};
return read_unique_id(chip, out_uid);
}{...}
static esp_err_t IRAM_ATTR detect_spi_flash_chip(esp_flash_t *chip)
{
esp_err_t err;
uint32_t flash_id = chip->chip_id;
const spi_flash_chip_t **drivers = esp_flash_registered_chips;
while (*drivers != NULL && !esp_flash_chip_driver_initialized(chip)) {
chip->chip_drv = *drivers;
ESP_EARLY_LOGD(TAG, "trying chip: %s", chip->chip_drv->name);
err = rom_spiflash_api_funcs->start(chip);
if (err != ESP_OK) {
return err;
}{...}
if (chip->chip_drv->probe(chip, flash_id) != ESP_OK) {
chip->chip_drv = NULL;
}{...}
drivers++;
err = rom_spiflash_api_funcs->end(chip, err);
if (err != ESP_OK) {
return err;
}{...}
}{...}
if (!esp_flash_chip_driver_initialized(chip)) {
return ESP_ERR_NOT_FOUND;
}{...}
ESP_EARLY_LOGI(TAG, "detected chip: %s", chip->chip_drv->name);
return ESP_OK;
}{...}
esp_err_t IRAM_ATTR esp_flash_get_physical_size(esp_flash_t *chip, uint32_t *flash_size)
{
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
if (err != ESP_OK) {
return err;
}{...}
VERIFY_CHIP_OP(detect_size);
if (flash_size == NULL) {
return ESP_ERR_INVALID_ARG;
}{...}
err = rom_spiflash_api_funcs->start(chip);
if (err != ESP_OK) {
return err;
}{...}
uint32_t detect_size;
err = chip->chip_drv->detect_size(chip, &detect_size);
if (err == ESP_OK) {
if (chip->size == 0) {
chip->size = detect_size;
}{...}
*flash_size = detect_size;
}{...}
return rom_spiflash_api_funcs->end(chip, err);
}{...}
#ifndef CONFIG_SPI_FLASH_ROM_IMPL
inline static bool regions_overlap(uint32_t a_start, uint32_t a_len,uint32_t b_start, uint32_t b_len);
esp_err_t IRAM_ATTR esp_flash_get_size(esp_flash_t *chip, uint32_t *out_size)
{
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
if (err != ESP_OK) {
return err;
}{...}
if (out_size == NULL) {
return ESP_ERR_INVALID_ARG;
}{...}
if (chip->size != 0) {
*out_size = chip->size;
return ESP_OK;
}{...}
return esp_flash_get_physical_size(chip, out_size);
}{...}
esp_err_t IRAM_ATTR esp_flash_erase_chip(esp_flash_t *chip)
{
esp_err_t err = ESP_OK;
uint32_t size = 0;
err = esp_flash_get_size(chip, &size);
if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_flash_get_size failed, flash error code: %d", err);
return err;
}{...}
err = esp_flash_erase_region(chip, 0, size);
return err;
}{...}
esp_err_t IRAM_ATTR esp_flash_erase_region(esp_flash_t *chip, uint32_t start, uint32_t len)
{
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
VERIFY_CHIP_OP(erase_sector);
VERIFY_CHIP_OP(erase_block);
CHECK_WRITE_ADDRESS(chip, start, len);
uint32_t block_erase_size = chip->chip_drv->erase_block == NULL ? 0 : chip->chip_drv->block_erase_size;
uint32_t sector_size = chip->chip_drv->sector_size;
COUNTER_START();
if (sector_size == 0 || (block_erase_size % sector_size) != 0) {
return ESP_ERR_FLASH_NOT_INITIALISED;
}{...}
if (start > chip->size || start + len > chip->size) {
return ESP_ERR_INVALID_ARG;
}{...}
if ((start % chip->chip_drv->sector_size) != 0 || (len % chip->chip_drv->sector_size) != 0) {
return ESP_ERR_INVALID_ARG;
}{...}
if (len == 0) {
return ESP_OK;
}{...}
err = ESP_OK;
if (chip->chip_drv->get_protected_regions != NULL &&
chip->chip_drv->num_protectable_regions > 0) {
err = rom_spiflash_api_funcs->start(chip);
if (err != ESP_OK) {
return err;
}{...}
uint64_t protected = 0;
err = chip->chip_drv->get_protected_regions(chip, &protected);
if (err == ESP_OK && protected != 0) {
for (int i = 0; i < chip->chip_drv->num_protectable_regions && err == ESP_OK; i++) {
const esp_flash_region_t *region = &chip->chip_drv->protectable_regions[i];
if ((protected & BIT64(i))
&& regions_overlap(start, len, region->offset, region->size)) {
err = ESP_ERR_FLASH_PROTECTED;
}{...}
}{...}
}{...}
err = rom_spiflash_api_funcs->end(chip, err);
}{...}
if (err != ESP_OK) {
return err;
}{...}
uint32_t erase_addr = start;
uint32_t len_remain = len;
bool bus_acquired = false;
while (1) {
if (chip->chip_drv->yield) {
err = chip->chip_drv->yield(chip, 0);
if (err != ESP_OK) {
return err;
}{...}
}{...}
err = rom_spiflash_api_funcs->start(chip);
if (err != ESP_OK) {
break;
}{...}
bus_acquired = true;
#ifndef CONFIG_SPI_FLASH_BYPASS_BLOCK_ERASE
if (block_erase_size > 0 && len_remain >= block_erase_size && (erase_addr % block_erase_size) == 0) {
err = chip->chip_drv->erase_block(chip, erase_addr);
erase_addr += block_erase_size;
len_remain -= block_erase_size;
COUNTER_ADD_BYTES(erase, block_erase_size);
}{...} else
#endif
{
err = chip->chip_drv->erase_sector(chip, erase_addr);
erase_addr += sector_size;
len_remain -= sector_size;
COUNTER_ADD_BYTES(erase, sector_size);
}{...}
assert(len_remain < len);
if (err != ESP_OK || len_remain == 0) {
assert(bus_acquired);
break;
}{...}
err = rom_spiflash_api_funcs->end(chip, ESP_OK);
if (err != ESP_OK) {
break;
}{...}
bus_acquired = false;
}{...}
COUNTER_STOP(erase);
return rom_spiflash_api_funcs->flash_end_flush_cache(chip, err, bus_acquired, start, len);
}{...}
/* ... */
#endif
#if defined(CONFIG_SPI_FLASH_ROM_IMPL) && ESP_ROM_HAS_ERASE_0_REGION_BUG
/* ... */
extern esp_err_t rom_esp_flash_erase_region(esp_flash_t *chip, uint32_t start, uint32_t len);
esp_err_t IRAM_ATTR esp_flash_erase_region(esp_flash_t *chip, uint32_t start, uint32_t len)
{
if (len == 0) {
return ESP_OK;
}{...}
return rom_esp_flash_erase_region(chip, start, len);
}{...}
/* ... */#endif
#ifndef CONFIG_SPI_FLASH_ROM_IMPL
esp_err_t IRAM_ATTR esp_flash_get_chip_write_protect(esp_flash_t *chip, bool *out_write_protected)
{
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
VERIFY_CHIP_OP(get_chip_write_protect);
if (out_write_protected == NULL) {
return ESP_ERR_INVALID_ARG;
}{...}
err = rom_spiflash_api_funcs->start(chip);
if (err != ESP_OK) {
return err;
}{...}
err = chip->chip_drv->get_chip_write_protect(chip, out_write_protected);
return rom_spiflash_api_funcs->end(chip, err);
}{...}
esp_err_t IRAM_ATTR esp_flash_set_chip_write_protect(esp_flash_t *chip, bool write_protect)
{
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
VERIFY_CHIP_OP(set_chip_write_protect);
err = rom_spiflash_api_funcs->start(chip);
if (err != ESP_OK) {
return err;
}{...}
err = chip->chip_drv->set_chip_write_protect(chip, write_protect);
return rom_spiflash_api_funcs->end(chip, err);
}{...}
esp_err_t esp_flash_get_protectable_regions(const esp_flash_t *chip, const esp_flash_region_t **out_regions, uint32_t *out_num_regions)
{
if(out_num_regions != NULL) {
*out_num_regions = 0;
}{...}
esp_err_t err = rom_spiflash_api_funcs->chip_check((esp_flash_t **)&chip);
VERIFY_CHIP_OP(get_protected_regions);
if(out_regions == NULL || out_num_regions == NULL) {
return ESP_ERR_INVALID_ARG;
}{...}
*out_num_regions = chip->chip_drv->num_protectable_regions;
*out_regions = chip->chip_drv->protectable_regions;
return ESP_OK;
}{...}
static esp_err_t find_region(const esp_flash_t *chip, const esp_flash_region_t *region, uint8_t *index)
{
if (region == NULL) {
return ESP_ERR_INVALID_ARG;
}{...}
for(*index = 0; *index < chip->chip_drv->num_protectable_regions; (*index)++) {
if (memcmp(&chip->chip_drv->protectable_regions[*index],
region, sizeof(esp_flash_region_t)) == 0) {
return ESP_OK;
}{...}
}{...}
return ESP_ERR_NOT_FOUND;
}{...}
esp_err_t IRAM_ATTR esp_flash_get_protected_region(esp_flash_t *chip, const esp_flash_region_t *region, bool *out_protected)
{
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
VERIFY_CHIP_OP(get_protected_regions);
if (out_protected == NULL) {
return ESP_ERR_INVALID_ARG;
}{...}
uint8_t index;
err = find_region(chip, region, &index);
if (err != ESP_OK) {
return err;
}{...}
uint64_t protection_mask = 0;
err = rom_spiflash_api_funcs->start(chip);
if (err != ESP_OK) {
return err;
}{...}
err = chip->chip_drv->get_protected_regions(chip, &protection_mask);
if (err == ESP_OK) {
*out_protected = protection_mask & (1LL << index);
}{...}
return rom_spiflash_api_funcs->end(chip, err);
}{...}
esp_err_t IRAM_ATTR esp_flash_set_protected_region(esp_flash_t *chip, const esp_flash_region_t *region, bool protect)
{
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
VERIFY_CHIP_OP(set_protected_regions);
uint8_t index;
err = find_region(chip, region, &index);
if (err != ESP_OK) {
return err;
}{...}
uint64_t protection_mask = 0;
err = rom_spiflash_api_funcs->start(chip);
if (err != ESP_OK) {
return err;
}{...}
err = chip->chip_drv->get_protected_regions(chip, &protection_mask);
if (err == ESP_OK) {
if (protect) {
protection_mask |= (1LL << index);
}{...} else {
protection_mask &= ~(1LL << index);
}{...}
err = chip->chip_drv->set_protected_regions(chip, protection_mask);
}{...}
return rom_spiflash_api_funcs->end(chip, err);
}{...}
esp_err_t IRAM_ATTR esp_flash_read(esp_flash_t *chip, void *buffer, uint32_t address, uint32_t length)
{
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
VERIFY_CHIP_OP(read);
if (buffer == NULL || address > chip->size || address+length > chip->size) {
return ESP_ERR_INVALID_ARG;
}{...}
if (length == 0) {
return ESP_OK;
}{...}
bool direct_read = false;
direct_read |= esp_ptr_in_dram(buffer);
direct_read |= chip->host->driver->supports_direct_read(chip->host, buffer);
uint8_t* temp_buffer = NULL;
size_t read_chunk_size = MIN(MAX_READ_CHUNK, length);
if (!direct_read) {
size_t actual_len = 0;
if (chip->os_func->get_temp_buffer != NULL) {
temp_buffer = chip->os_func->get_temp_buffer(chip->os_func_data, read_chunk_size, &actual_len);
read_chunk_size = actual_len;
}{...}
if (temp_buffer == NULL) {
return ESP_ERR_NO_MEM;
}{...}
}{...}
COUNTER_START();
err = ESP_OK;
do {
err = rom_spiflash_api_funcs->start(chip);
if (err != ESP_OK) {
break;
}{...}
uint8_t* buffer_to_read = (temp_buffer)? temp_buffer : buffer;
size_t length_to_read = MIN(read_chunk_size, length);
if (err == ESP_OK) {
err = chip->chip_drv->read(chip, buffer_to_read, address, length_to_read);
}{...}
if (err != ESP_OK) {
rom_spiflash_api_funcs->end(chip, err);
break;
}{...}
err = rom_spiflash_api_funcs->end(chip, err);
if (temp_buffer) {
memcpy(buffer, temp_buffer, length_to_read);
}{...}
address += length_to_read;
length -= length_to_read;
buffer = (void*)((intptr_t)buffer + length_to_read);
COUNTER_ADD_BYTES(read, length_to_read);
}{...} while (err == ESP_OK && length > 0);
if (chip->os_func->release_temp_buffer != NULL) {
chip->os_func->release_temp_buffer(chip->os_func_data, temp_buffer);
}{...}
COUNTER_STOP(read);
return err;
}{...}
#if CONFIG_SPI_FLASH_WARN_SETTING_ZERO_TO_ONE
static esp_err_t IRAM_ATTR s_check_setting_zero_to_one(esp_flash_t *chip, uint32_t verify_address, uint32_t remain_verify_len, const uint32_t *to_write_buf, bool is_encrypted)
{
esp_err_t err = ESP_FAIL;
uint8_t verify_buffer[VERIFY_BUF_LEN];
uint32_t *val_in_flash = (uint32_t *)verify_buffer;
while (remain_verify_len) {
uint32_t this_len = MIN(remain_verify_len, VERIFY_BUF_LEN);
err = chip->chip_drv->read(chip, verify_buffer, verify_address, this_len);
if (err != ESP_OK) {
ESP_DRAM_LOGE(TAG, "failed to read flash to verify if setting zero to one, err: 0x%x", err);
return err;
}{...}
for (int r = 0; r < this_len / sizeof(uint32_t); r++) {
if (is_encrypted) {
(void)to_write_buf;
if (val_in_flash[r] != 0xFFFFFFFF) {
ESP_DRAM_LOGW(TAG, "Write at offset 0x%x but not erased (0x%08x)",
verify_address + r, val_in_flash[r]);
}{...}
}{...} else {
if ((val_in_flash[r] & to_write_buf[r]) != to_write_buf[r]) {
ESP_DRAM_LOGW(TAG, "Write at offset 0x%x requests 0x%08x but will write 0x%08x -> 0x%08x",
verify_address + r, to_write_buf[r], val_in_flash[r], (val_in_flash[r] & to_write_buf[r]));
}{...}
}{...}
}{...}
remain_verify_len -= this_len;
verify_address += this_len;
}{...}
return ESP_OK;
}{...}
/* ... */#endif
#if CONFIG_SPI_FLASH_VERIFY_WRITE
static esp_err_t IRAM_ATTR s_verify_write(esp_flash_t *chip, uint32_t verify_address, uint32_t remain_verify_len, const uint32_t *expected_buf, bool is_encrypted)
{
esp_err_t err = ESP_FAIL;
uint8_t verify_buffer[VERIFY_BUF_LEN];
uint32_t *val_in_flash = (uint32_t *)verify_buffer;
while (remain_verify_len) {
uint32_t this_len = MIN(remain_verify_len, VERIFY_BUF_LEN);
if (is_encrypted) {
err = esp_flash_read_encrypted(chip, verify_address, verify_buffer, this_len);
}{...} else {
err = chip->chip_drv->read(chip, verify_buffer, verify_address, this_len);
}{...}
if (err != ESP_OK) {
ESP_DRAM_LOGE(TAG, "failed to read flash to verify previous write, err: 0x%x", err);
return err;
}{...}
for (int r = 0; r < this_len / sizeof(uint32_t); r++) {
if (val_in_flash[r] != expected_buf[r]) {
#if CONFIG_SPI_FLASH_LOG_FAILED_WRITE
ESP_DRAM_LOGE(TAG, "Bad write at %d offset: 0x%x, expected: 0x%08x, readback: 0x%08x", r, verify_address + r, expected_buf[r], val_in_flash[r]);
#endif
return ESP_FAIL;
}{...}
}{...}
expected_buf = (uint32_t *)((void *)expected_buf + this_len);
remain_verify_len -= this_len;
verify_address += this_len;
}{...}
return ESP_OK;
}{...}
/* ... */#endif
esp_err_t IRAM_ATTR esp_flash_write(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length)
{
esp_err_t ret = ESP_FAIL;
#if CONFIG_SPI_FLASH_VERIFY_WRITE
bool is_encrypted = false;/* ... */
#endif
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
VERIFY_CHIP_OP(write);
CHECK_WRITE_ADDRESS(chip, address, length);
if (buffer == NULL || address > chip->size || address+length > chip->size) {
return ESP_ERR_INVALID_ARG;
}{...}
if (length == 0) {
return ESP_OK;
}{...}
bool direct_write = false;
direct_write |= esp_ptr_in_dram(buffer);
direct_write |= chip->host->driver->supports_direct_write(chip->host, buffer);
bool bus_acquired = false;
err = ESP_OK;
COUNTER_START();
/* ... */
uint32_t write_addr = address;
uint32_t len_remain = length;
while (1) {
uint32_t write_len;
const void *write_buf;
uint32_t temp_buf[8];
if (direct_write) {
write_len = MIN(len_remain, MAX_WRITE_CHUNK);
write_buf = buffer;
}{...} else {
write_len = MIN(len_remain, sizeof(temp_buf));
memcpy(temp_buf, buffer, write_len);
write_buf = temp_buf;
}{...}
if (chip->chip_drv->yield) {
err = chip->chip_drv->yield(chip, 0);
if (err != ESP_OK) {
return err;
}{...}
}{...}
err = rom_spiflash_api_funcs->start(chip);
if (err != ESP_OK) {
goto restore_cache;
}{...}
bus_acquired = true;
#if CONFIG_SPI_FLASH_WARN_SETTING_ZERO_TO_ONE
err = s_check_setting_zero_to_one(chip, write_addr, write_len, write_buf, is_encrypted);
if (err != ESP_OK) {
goto restore_cache;
}{...}
/* ... */#endif
err = chip->chip_drv->write(chip, write_buf, write_addr, write_len);
len_remain -= write_len;
assert(len_remain < length);
COUNTER_ADD_BYTES(write, write_len);
if (err != ESP_OK) {
assert(bus_acquired);
goto restore_cache;
}{...}
#if CONFIG_SPI_FLASH_VERIFY_WRITE
err = s_verify_write(chip, write_addr, write_len, write_buf, is_encrypted);
if (err != ESP_OK) {
goto restore_cache;
}{...}
/* ... */#endif
if (len_remain == 0) {
break;
}{...}
err = rom_spiflash_api_funcs->end(chip, err);
if (err != ESP_OK) {
goto restore_cache;
}{...}
bus_acquired = false;
write_addr += write_len;
buffer = (void *)((intptr_t)buffer + write_len);
}{...}
COUNTER_STOP(write);
err = rom_spiflash_api_funcs->flash_end_flush_cache(chip, err, bus_acquired, address, length);
return err;
restore_cache:
COUNTER_STOP(write);
ret = rom_spiflash_api_funcs->flash_end_flush_cache(chip, err, bus_acquired, address, length);
if (ret != ESP_OK) {
ESP_DRAM_LOGE(TAG, "restore cache fail\n");
}{...}
return err;
}{...}
inline static IRAM_ATTR bool regions_overlap(uint32_t a_start, uint32_t a_len,uint32_t b_start, uint32_t b_len)
{
uint32_t a_end = a_start + a_len;
uint32_t b_end = b_start + b_len;
return (a_end > b_start && b_end > a_start);
}{...}
esp_err_t IRAM_ATTR esp_flash_read_encrypted(esp_flash_t *chip, uint32_t address, void *out_buffer, uint32_t length)
{
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
if (err != ESP_OK) return err;
if (address + length > g_rom_flashchip.chip_size) {
return ESP_ERR_INVALID_SIZE;
}{...}
if (length == 0) {
return ESP_OK;
}{...}
if (out_buffer == NULL) {
return ESP_ERR_INVALID_ARG;
}{...}
COUNTER_START();
const uint8_t *map;
spi_flash_mmap_handle_t map_handle;
size_t map_src = address & ~(SPI_FLASH_MMU_PAGE_SIZE - 1);
size_t map_size = length + (address - map_src);
err = spi_flash_mmap(map_src, map_size, SPI_FLASH_MMAP_DATA, (const void **)&map, &map_handle);
if (err != ESP_OK) {
return err;
}{...}
memcpy(out_buffer, map + (address - map_src), length);
spi_flash_munmap(map_handle);
COUNTER_ADD_BYTES(read, length);
COUNTER_STOP(read);
return err;
}{...}
IRAM_ATTR esp_err_t esp_flash_get_io_mode(esp_flash_t* chip, bool* qe)
{
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
VERIFY_CHIP_OP(get_io_mode);
esp_flash_io_mode_t io_mode;
err = rom_spiflash_api_funcs->start(chip);
if (err != ESP_OK) {
return err;
}{...}
err = chip->chip_drv->get_io_mode(chip, &io_mode);
err = rom_spiflash_api_funcs->end(chip, err);
if (err == ESP_OK) {
*qe = (io_mode == SPI_FLASH_QOUT);
}{...}
return err;
}{...}
IRAM_ATTR esp_err_t esp_flash_set_io_mode(esp_flash_t* chip, bool qe)
{
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
VERIFY_CHIP_OP(set_io_mode);
chip->read_mode = (qe? SPI_FLASH_QOUT: SPI_FLASH_SLOWRD);
err = rom_spiflash_api_funcs->start(chip);
if (err != ESP_OK) {
return err;
}{...}
err = chip->chip_drv->set_io_mode(chip);
return rom_spiflash_api_funcs->end(chip, err);
}{...}
/* ... */#endif
#if !CONFIG_SPI_FLASH_ROM_IMPL || ESP_ROM_HAS_ENCRYPTED_WRITES_USING_LEGACY_DRV
FORCE_INLINE_ATTR esp_err_t s_encryption_write_lock(esp_flash_t *chip) {
#if CONFIG_IDF_TARGET_ESP32S2
esp_crypto_dma_lock_acquire();
#endif
return rom_spiflash_api_funcs->start(chip);
}{...}
FORCE_INLINE_ATTR esp_err_t s_encryption_write_unlock(esp_flash_t *chip) {
esp_err_t err = rom_spiflash_api_funcs->end(chip, ESP_OK);
#if CONFIG_IDF_TARGET_ESP32S2
esp_crypto_dma_lock_release();
#endif
return err;
}{...}
esp_err_t IRAM_ATTR esp_flash_write_encrypted(esp_flash_t *chip, uint32_t address, const void *buffer, uint32_t length)
{
esp_err_t ret = ESP_FAIL;
#if CONFIG_SPI_FLASH_VERIFY_WRITE
bool is_encrypted = true;/* ... */
#endif
esp_err_t err = rom_spiflash_api_funcs->chip_check(&chip);
VERIFY_CHIP_OP(write);
if (chip != esp_flash_default_chip) {
return ESP_ERR_NOT_SUPPORTED;
}{...}
CHECK_WRITE_ADDRESS(chip, address, length);
if (buffer == NULL || address + length > chip->size) {
return ESP_ERR_INVALID_ARG;
}{...}
if ((address % 16) != 0) {
ESP_DRAM_LOGE(TAG, "flash encrypted write address must be 16 bytes aligned");
return ESP_ERR_INVALID_ARG;
}{...}
if (length == 0) {
return ESP_OK;
}{...}
if ((length % 16) != 0) {
ESP_DRAM_LOGE(TAG, "flash encrypted write length must be multiple of 16");
return ESP_ERR_INVALID_SIZE;
}{...}
bool bus_acquired = false;
bool lock_once = true;
const uint8_t *ssrc = (const uint8_t *)buffer;
/* ... */
lock_once = esp_ptr_in_dram(buffer);
COUNTER_START();
/* ... */
uint8_t encrypt_buf[64] __attribute__((aligned(4)));
uint32_t row_size_length;
#if CONFIG_IDF_TARGET_ESP32
uint8_t pre_buf[16] = {0};
uint8_t post_buf[16] = {0};
if((address % 32) != 0) {
esp_flash_read_encrypted(chip, address - 16, pre_buf, 16);
}{...}
if(((address + length) % 32) != 0) {
esp_flash_read_encrypted(chip, address + length, post_buf, 16);
}{...}
/* ... */#endif
if (lock_once == true) {
err = s_encryption_write_lock(chip);
if (err != ESP_OK) {
ESP_DRAM_LOGE(TAG, "flash acquire lock failed");
return err;
}{...}
bus_acquired = true;
}{...}
for (size_t i = 0; i < length; i += row_size_length) {
uint32_t row_addr = address + i;
uint8_t row_size;
uint8_t encrypt_byte;
#if CONFIG_IDF_TARGET_ESP32
if (i == 0 && (row_addr % 32) != 0) {
row_size = 16;
row_addr -= 16;
memcpy(encrypt_buf + 16, ssrc + i, row_size);
memcpy(encrypt_buf, pre_buf, 16);
}{...} else if (length - i == 16) {
row_size = 16;
memcpy(encrypt_buf, ssrc + i, row_size);
memcpy(encrypt_buf + 16, post_buf, 16);
}{...} else {
row_size = 32;
memcpy(encrypt_buf, ssrc + i, row_size);
}{...}
encrypt_byte = 32;
row_size_length = row_size;/* ... */
#else
if ((row_addr % 64) == 0 && (length - i) >= 64 && SOC_FLASH_ENCRYPTED_XTS_AES_BLOCK_MAX == 64) {
row_size = 64;
memcpy(encrypt_buf, ssrc + i, row_size);
}{...} else if ((row_addr % 32) == 0 && (length - i) >= 32) {
row_size = 32;
memcpy(encrypt_buf, ssrc + i, row_size);
}{...} else {
row_size = 16;
memcpy(encrypt_buf, ssrc + i, row_size);
}{...}
encrypt_byte = row_size;
row_size_length = row_size;/* ... */
#endif
#if CONFIG_SPI_FLASH_WARN_SETTING_ZERO_TO_ONE
err = s_check_setting_zero_to_one(chip, row_addr, encrypt_byte, NULL, is_encrypted);
if (err != ESP_OK) {
rom_spiflash_api_funcs->end(chip, ESP_OK);
#if CONFIG_IDF_TARGET_ESP32S2
esp_crypto_dma_lock_release();
#endif
goto restore_cache;
}{...}
/* ... */#endif
if (lock_once == false) {
err = s_encryption_write_lock(chip);
if (err != ESP_OK) {
goto restore_cache;
}{...}
bus_acquired = true;
}{...}
err = chip->chip_drv->write_encrypted(chip, (uint32_t *)encrypt_buf, row_addr, encrypt_byte);
if (err!= ESP_OK) {
goto restore_cache;
}{...}
if (lock_once == false) {
err = s_encryption_write_unlock(chip);
if (err != ESP_OK) {
bus_acquired = false;
goto restore_cache;
}{...}
bus_acquired = false;
}{...}
COUNTER_ADD_BYTES(write, encrypt_byte);
#if CONFIG_SPI_FLASH_VERIFY_WRITE
err = s_verify_write(chip, row_addr, encrypt_byte, (uint32_t *)encrypt_buf, is_encrypted);
if (err != ESP_OK) {
goto restore_cache;
}{...}
/* ... */#endif
}{...}
if (lock_once == true) {
err = s_encryption_write_unlock(chip);
if (err != ESP_OK) {
bus_acquired = false;
goto restore_cache;
}{...}
}{...}
bus_acquired = false;
COUNTER_STOP(write);
err = rom_spiflash_api_funcs->flash_end_flush_cache(chip, err, bus_acquired, address, length);
return err;
restore_cache:
s_encryption_write_unlock(chip);
bus_acquired = false;
COUNTER_STOP(write);
ret = rom_spiflash_api_funcs->flash_end_flush_cache(chip, err, bus_acquired, address, length);
if (ret != ESP_OK) {
ESP_DRAM_LOGE(TAG, "restore cache fail\n");
}{...}
return err;
}{...}
/* ... */
#endif
esp_err_t esp_flash_suspend_cmd_init(esp_flash_t* chip)
{
ESP_EARLY_LOGW(TAG, "Flash suspend feature is enabled");
if (chip->chip_drv->get_chip_caps == NULL) {
ESP_EARLY_LOGW(TAG, "get_chip_caps function pointer hasn't been initialized");
}{...} else {
if ((chip->chip_drv->get_chip_caps(chip) & SPI_FLASH_CHIP_CAP_SUSPEND) == 0) {
ESP_EARLY_LOGW(TAG, "Suspend and resume may not supported for this flash model yet.");
}{...}
}{...}
return chip->chip_drv->sus_setup(chip);
}{...}
esp_err_t esp_flash_app_disable_protect(bool disable)
{
if (disable) {
return esp_flash_app_disable_os_functions(esp_flash_default_chip);
}{...} else {
return esp_flash_app_enable_os_functions(esp_flash_default_chip);
}{...}
}{...}