Select one of the symbols to view example projects that use it.
 
Outline
#include <stdlib.h>
#include <string.h>
#include "sdkconfig.h"
#include "esp_attr.h"
#include "esp_err.h"
#include "esp_types.h"
#include "esp_log.h"
#include "soc/io_mux_reg.h"
#include "soc/soc.h"
#include "hal/spi_flash_hal.h"
#include "hal/cache_hal.h"
#include "hal/cache_ll.h"
#include "esp_private/mspi_timing_tuning.h"
#include "esp_private/mspi_timing_config.h"
#include "mspi_timing_by_mspi_delay.h"
#include "mspi_timing_by_dqs.h"
#include "mspi_timing_tuning_configs.h"
#include "hal/mspi_timing_tuning_ll.h"
#include "hal/spimem_flash_ll.h"
#include "hal/mspi_timing_tuning_ll.h"
#include "esp_ipc_isr.h"
#define FLASH_FREQUENCY_MHZ
#define FLASH_FREQUENCY_MHZ
#define FLASH_FREQUENCY_MHZ
#define FLASH_FREQUENCY_MHZ
#define FLASH_FREQUENCY_MHZ
#define FLASH_FREQUENCY_MHZ
#define FLASH_FREQUENCY_MHZ
#define FLASH_FREQUENCY_MHZ
#define FLASH_FREQUENCY_MHZ
#define FLASH_FREQUENCY_MHZ
#define FLASH_FREQUENCY_MHZ
#define FLASH_FREQUENCY_MHZ
#define FLASH_FREQUENCY_MHZ
mspi_timing_tuning_t
mspi_tuning_cfg_drv_s
TAG
mspi_tuning_cfg_drv_s
s_tuning_cfg_drv
s_register_config_driver(mspi_tuning_cfg_drv_t *, bool)
mspi_timing_flash_tuning()
mspi_timing_psram_tuning()
mspi_timing_enter_low_speed_mode(bool)
mspi_timing_enter_high_speed_mode(bool)
mspi_timing_change_speed_mode_cache_safe(bool)
spi_flash_timing_is_tuned()
spi_timing_get_flash_timing_param(spi_flash_hal_timing_config_t *)
mspi_timing_set_pin_drive_strength()
Files
loading (3/5)...
SourceVuESP-IDF Framework and ExamplesESP-IDFcomponents/esp_hw_support/mspi_timing_tuning.c
 
1
2
3
4
5
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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/* * SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 *//* ... */ #include <stdlib.h> #include <string.h> #include "sdkconfig.h" #include "esp_attr.h" #include "esp_err.h" #include "esp_types.h" #include "esp_log.h" #include "soc/io_mux_reg.h" #include "soc/soc.h" #include "hal/spi_flash_hal.h" #include "hal/cache_hal.h" #include "hal/cache_ll.h" #include "esp_private/mspi_timing_tuning.h" #include "esp_private/mspi_timing_config.h" #include "mspi_timing_by_mspi_delay.h" #include "mspi_timing_by_dqs.h"16 includes #if SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY || SOC_MEMSPI_TIMING_TUNING_BY_DQS #include "mspi_timing_tuning_configs.h" #include "hal/mspi_timing_tuning_ll.h"/* ... */ #endif #if SOC_MEMSPI_CLK_SRC_IS_INDEPENDENT #include "hal/spimem_flash_ll.h" #endif #if CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C61 // TODO: IDF-10464 #include "hal/mspi_timing_tuning_ll.h" #endif #if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE #include "esp_ipc_isr.h" #endif #if CONFIG_ESPTOOLPY_FLASHFREQ_120M #define FLASH_FREQUENCY_MHZ 120 #elif CONFIG_ESPTOOLPY_FLASHFREQ_80M #define FLASH_FREQUENCY_MHZ 80 #elif CONFIG_ESPTOOLPY_FLASHFREQ_64M #define FLASH_FREQUENCY_MHZ 64 #elif CONFIG_ESPTOOLPY_FLASHFREQ_60M #define FLASH_FREQUENCY_MHZ 60 #elif CONFIG_ESPTOOLPY_FLASHFREQ_48M #define FLASH_FREQUENCY_MHZ 48 #elif CONFIG_ESPTOOLPY_FLASHFREQ_40M #define FLASH_FREQUENCY_MHZ 40 #elif CONFIG_ESPTOOLPY_FLASHFREQ_32M #define FLASH_FREQUENCY_MHZ 32 #elif CONFIG_ESPTOOLPY_FLASHFREQ_30M #define FLASH_FREQUENCY_MHZ 30 #elif CONFIG_ESPTOOLPY_FLASHFREQ_26M #define FLASH_FREQUENCY_MHZ 26 #elif CONFIG_ESPTOOLPY_FLASHFREQ_24M #define FLASH_FREQUENCY_MHZ 24 #elif CONFIG_ESPTOOLPY_FLASHFREQ_20M #define FLASH_FREQUENCY_MHZ 20 #elif CONFIG_ESPTOOLPY_FLASHFREQ_16M #define FLASH_FREQUENCY_MHZ 16 #elif CONFIG_ESPTOOLPY_FLASHFREQ_15M #define FLASH_FREQUENCY_MHZ 15 #endif /** * @brief MSPI timing tuning type *//* ... */ typedef enum { MSPI_TIMING_TUNING_MSPI_DIN_DUMMY, //tune by mspi din and dummy MSPI_TIMING_TUNING_MSPI_DQS_PHASE, //tune by mspi dqs phase MSPI_TIMING_TUNING_MSPI_DELAYLINE, //tune by mspi delayline }{ ... } mspi_timing_tuning_t; typedef struct mspi_tuning_cfg_drv_s mspi_tuning_cfg_drv_t; __attribute__((unused)) const static char *TAG = "MSPI Timing"; struct mspi_tuning_cfg_drv_s { /** * @brief Flash tuning scheme type *//* ... */ mspi_timing_tuning_t flash_tuning_type; /** * @brief How many test times during sweep *//* ... */ uint32_t sweep_test_nums; /** * @brief Init MSPI for Flash timing tuning * * @param[in] flash_freq_mhz Flash frequency in MHz *//* ... */ void (*flash_init_mspi)(uint32_t flash_freq_mhz); /** * @brief Configure MSPI for Flash timing tuning * * @param[in] configs Timing tuning configs * @param[in] id Config ID *//* ... */ void (*flash_tune_mspi)(const void *configs, uint8_t id); /** * @brief Flash read * * @param[in] buf Read buffer * @param[in] addr Read address * @param[in] len Read length *//* ... */ void (*flash_read)(uint8_t *buf, uint32_t addr, uint32_t len); /** * @brief Select best tuning configs for Flash * * @param[in] configs Timing tuning configurations * @param[in] consecutive_length Length of the consecutive successful sample results * @param[in] end End of the consecutive successful sample results * @param[in] reference_data Reference data * @param[in] is_ddr DDR or SDR * * @return Best config ID *//* ... */ uint32_t (*flash_select_best_tuning_config)(const void *configs, uint32_t consecutive_length, uint32_t end, const uint8_t *reference_data, bool is_ddr); /** * @brief Set best Flash tuning configs. * After this, calling `mspi_timing_enter_high_speed_mode` will set these configs correctly * * @param[in] configs Timing tuning configs * @param[in] best_id Best config ID *//* ... */ void (*flash_set_best_tuning_config)(const void *configs, uint8_t best_id); /** * @brief PSRAM tuning scheme type *//* ... */ mspi_timing_tuning_t psram_tuning_type; /** * @brief Init MSPI for PSRAM timing tuning * * @param[in] flash_freq_mhz PSRAM frequency in MHz *//* ... */ void (*psram_init_mspi)(uint32_t psram_freq_mhz); /** * @brief Configure MSPI for PSRAM timing tuning * * @param[in] configs Timing tuning configs * @param[in] id Config ID *//* ... */ void (*psram_tune_mspi)(const void *configs, uint8_t id); /** * @brief PSRAM read * * @param[in] buf Read buffer * @param[in] addr Read address * @param[in] len Read length *//* ... */ void (*psram_read)(uint8_t *buf, uint32_t addr, uint32_t len); /** * @brief Select best tuning configs for PSRAM * * @param[in] configs Timing tuning configurations * @param[in] consecutive_length Length of the consecutive successful sample results * @param[in] end End of the consecutive successful sample results * @param[in] reference_data Reference data * @param[in] is_ddr DDR or SDR * * @return Best config ID *//* ... */ uint32_t (*psram_select_best_tuning_config)(const void *configs, uint32_t consecutive_length, uint32_t end, const uint8_t *reference_data, bool is_ddr); /** * @brief Set best PSRAM tuning configs. * After this, calling `mspi_timing_enter_high_speed_mode` will set these configs correctly * * @param[in] configs Timing tuning config * @param[in] best_id Best config ID *//* ... */ void (*psram_set_best_tuning_config)(const void *configs, uint8_t best_id); }{ ... }; static mspi_tuning_cfg_drv_t s_tuning_cfg_drv = {}; void s_register_config_driver(mspi_tuning_cfg_drv_t *cfg_drv, bool is_flash) { if (is_flash) { s_tuning_cfg_drv.flash_tuning_type = cfg_drv->flash_tuning_type; s_tuning_cfg_drv.flash_init_mspi = cfg_drv->flash_init_mspi; s_tuning_cfg_drv.flash_tune_mspi = cfg_drv->flash_tune_mspi; s_tuning_cfg_drv.flash_read = cfg_drv->flash_read; s_tuning_cfg_drv.flash_select_best_tuning_config = cfg_drv->flash_select_best_tuning_config; s_tuning_cfg_drv.flash_set_best_tuning_config = cfg_drv->flash_set_best_tuning_config; }{...} else { s_tuning_cfg_drv.psram_tuning_type = cfg_drv->psram_tuning_type; s_tuning_cfg_drv.psram_init_mspi = cfg_drv->psram_init_mspi; s_tuning_cfg_drv.psram_tune_mspi = cfg_drv->psram_tune_mspi; s_tuning_cfg_drv.psram_read = cfg_drv->psram_read; s_tuning_cfg_drv.psram_select_best_tuning_config = cfg_drv->psram_select_best_tuning_config; s_tuning_cfg_drv.psram_set_best_tuning_config = cfg_drv->psram_set_best_tuning_config; }{...} s_tuning_cfg_drv.sweep_test_nums = cfg_drv->sweep_test_nums; }{ ... } #if MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING /** * We use different MSPI timing tuning config to read data to see if current MSPI sampling is successful. * The sampling result will be stored in an array. In this array, successful item will be 1, failed item will be 0. *//* ... */ static void s_sweep_for_success_sample_points(uint8_t *reference_data, void *config, bool is_flash, uint32_t *out_array) { const mspi_timing_config_t *timing_config = (const mspi_timing_config_t *)config; uint32_t config_idx = 0; uint8_t read_data[MSPI_TIMING_TEST_DATA_LEN] = {0}; for (config_idx = 0; config_idx < timing_config->available_config_num; config_idx++) { out_array[config_idx] = 0; for (int i = 0; i < s_tuning_cfg_drv.sweep_test_nums; i++) { memset(read_data, 0, MSPI_TIMING_TEST_DATA_LEN); #if MSPI_TIMING_FLASH_NEEDS_TUNING if (is_flash) { s_tuning_cfg_drv.flash_tune_mspi(timing_config, config_idx); s_tuning_cfg_drv.flash_read(read_data, MSPI_TIMING_FLASH_TEST_DATA_ADDR, sizeof(read_data)); }{...} /* ... */#endif #if MSPI_TIMING_PSRAM_NEEDS_TUNING if (!is_flash) { s_tuning_cfg_drv.psram_tune_mspi(timing_config, config_idx); s_tuning_cfg_drv.psram_read(read_data, MSPI_TIMING_PSRAM_TEST_DATA_ADDR, MSPI_TIMING_TEST_DATA_LEN); }{...} /* ... */#endif if (memcmp(reference_data, read_data, sizeof(read_data)) == 0) { out_array[config_idx] += 1; }{...} }{...} }{...} ESP_EARLY_LOGD(TAG, "test nums: %" PRIu32 ", test result: [id][good/bad][good_times]:", s_tuning_cfg_drv.sweep_test_nums); for (config_idx = 0; config_idx < timing_config->available_config_num; config_idx++) { ESP_EARLY_LOGD(TAG, "[%"PRIu32"][%s][%" PRIu32 "] ", config_idx, out_array[config_idx] == s_tuning_cfg_drv.sweep_test_nums ? "good" : "bad", out_array[config_idx]); }{...} }{...} /** * Find consecutive successful sampling points. * e.g. array: {1, 1, 0, 0, 1, 1, 1, 0} * out_length: 3 * outout_end_index: 6 *//* ... */ static void s_find_max_consecutive_success_points(uint32_t *array, uint32_t size, uint32_t *out_length, uint32_t *out_end_index) { uint32_t max = 0; uint32_t match_num = 0; uint32_t i = 0; uint32_t end = 0; while (i < size) { if (array[i] == s_tuning_cfg_drv.sweep_test_nums) { match_num++; }{...} else { if (match_num > max) { max = match_num; end = i - 1; }{...} match_num = 0; }{...} i++; }{...} *out_length = match_num > max ? match_num : max; *out_end_index = match_num == size ? size : end; }{...} static void s_select_best_tuning_config(mspi_timing_config_t *config, uint32_t consecutive_length, uint32_t end, const uint8_t *reference_data, bool is_flash) { const mspi_timing_config_t *timing_config = (const mspi_timing_config_t *)config; uint32_t best_point = 0; if (is_flash) { #if MSPI_TIMING_FLASH_DTR_MODE best_point = s_tuning_cfg_drv.flash_select_best_tuning_config(timing_config, consecutive_length, end, reference_data, IS_DDR); #elif MSPI_TIMING_FLASH_STR_MODE best_point = s_tuning_cfg_drv.flash_select_best_tuning_config(timing_config, consecutive_length, end, NULL, IS_SDR); #endif s_tuning_cfg_drv.flash_set_best_tuning_config(timing_config, best_point); }{...} else { #if MSPI_TIMING_PSRAM_DTR_MODE best_point = s_tuning_cfg_drv.psram_select_best_tuning_config(timing_config, consecutive_length, end, reference_data, IS_DDR); #if CONFIG_SPIRAM_TIMING_TUNING_POINT_VIA_TEMPERATURE_SENSOR mspi_timing_setting_temperature_adjustment_best_point(best_point); #endif/* ... */ #elif MSPI_TIMING_PSRAM_STR_MODE best_point = s_tuning_cfg_drv.psram_select_best_tuning_config(timing_config, consecutive_length, end, NULL, IS_SDR); #endif s_tuning_cfg_drv.psram_set_best_tuning_config(timing_config, best_point); }{...} }{...} static void s_do_tuning(uint8_t *reference_data, mspi_timing_config_t *config, bool is_flash) { /** * We use MSPI to tune the timing: * 1. Get all MSPI sampling results. * 2. Find the longest consecutive successful sampling points from the result above. * 3. The middle one will be the best sampling point. *//* ... */ uint32_t consecutive_length = 0; uint32_t last_success_point = 0; uint32_t sample_result[MSPI_TIMING_CONFIG_NUM_MAX] = {0}; #if MSPI_TIMING_FLASH_NEEDS_TUNING if (is_flash) { s_tuning_cfg_drv.flash_init_mspi(FLASH_FREQUENCY_MHZ); }{...} /* ... */#endif #if MSPI_TIMING_PSRAM_NEEDS_TUNING if (!is_flash) { s_tuning_cfg_drv.psram_init_mspi(CONFIG_SPIRAM_SPEED); }{...} /* ... */#endif s_sweep_for_success_sample_points(reference_data, config, is_flash, sample_result); s_find_max_consecutive_success_points(sample_result, config->available_config_num, &consecutive_length, &last_success_point); s_select_best_tuning_config(config, consecutive_length, last_success_point, reference_data, is_flash); }{...} /* ... */#endif //#if MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING /*------------------------------------------------------------------------------ * FLASH Timing Tuning *----------------------------------------------------------------------------*//* ... */ #if MSPI_TIMING_FLASH_NEEDS_TUNING void mspi_timing_flash_tuning(void) { /** * set MSPI related regs to 20mhz configuration, to get reference data from FLASH * see detailed comments in this function (`mspi_timing_enter_low_speed_mode`) *//* ... */ mspi_timing_enter_low_speed_mode(true); #if SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY mspi_tuning_cfg_drv_t drv = { .flash_tuning_type = MSPI_TIMING_TUNING_MSPI_DIN_DUMMY, .sweep_test_nums = 1, .flash_init_mspi = mspi_timing_flash_init, .flash_tune_mspi = mspi_timing_config_flash_set_tuning_regs, .flash_read = mspi_timing_config_flash_read_data, .flash_select_best_tuning_config = mspi_timing_flash_select_best_tuning_config, .flash_set_best_tuning_config = mspi_timing_flash_set_best_tuning_config, }{...}; bool is_flash = true; s_register_config_driver(&drv, is_flash); //Disable the variable dummy mode when doing timing tuning mspi_timing_ll_enable_flash_variable_dummy(1, false); //GD flash will read error in variable mode with 20MHz uint8_t reference_data[MSPI_TIMING_TEST_DATA_LEN] = {0}; s_tuning_cfg_drv.flash_read(reference_data, MSPI_TIMING_FLASH_TEST_DATA_ADDR, sizeof(reference_data)); mspi_timing_config_t timing_configs = {0}; mspi_timing_get_flash_tuning_configs(&timing_configs); /* ... */ #endif //SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY s_do_tuning(reference_data, &timing_configs, true); mspi_timing_enter_high_speed_mode(true); }{...} /* ... */#else void mspi_timing_flash_tuning(void) { //Empty function for compatibility, therefore upper layer won't need to know that FLASH in which operation mode and frequency config needs to be tuned }{ ... } /* ... */#endif //MSPI_TIMING_FLASH_NEEDS_TUNING /*------------------------------------------------------------------------------ * PSRAM Timing Tuning *----------------------------------------------------------------------------*//* ... */ #if MSPI_TIMING_PSRAM_NEEDS_TUNING void mspi_timing_psram_tuning(void) { /** * set MSPI related regs to 20mhz configuration, to write reference data to PSRAM * see detailed comments in this function (`mspi_timing_enter_low_speed_mode`) *//* ... */ mspi_timing_enter_low_speed_mode(true); // write data into psram, used to do timing tuning test. uint8_t reference_data[MSPI_TIMING_TEST_DATA_LEN]; mspi_timing_config_psram_prepare_reference_data(reference_data, MSPI_TIMING_TEST_DATA_LEN); mspi_timing_config_psram_write_data(reference_data, MSPI_TIMING_PSRAM_TEST_DATA_ADDR, MSPI_TIMING_TEST_DATA_LEN); #if SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY mspi_tuning_cfg_drv_t drv = { .psram_tuning_type = MSPI_TIMING_TUNING_MSPI_DIN_DUMMY, .sweep_test_nums = 1, .psram_init_mspi = mspi_timing_psram_init, .psram_tune_mspi = mspi_timing_config_psram_set_tuning_regs, .psram_read = mspi_timing_config_psram_read_data, .psram_select_best_tuning_config = mspi_timing_psram_select_best_tuning_config, .psram_set_best_tuning_config = mspi_timing_psram_set_best_tuning_config, }{...}; bool is_flash = false; s_register_config_driver(&drv, is_flash); mspi_timing_config_t timing_configs = {}; mspi_timing_get_psram_tuning_configs(&timing_configs); //Disable the variable dummy mode when doing timing tuning mspi_timing_ll_enable_flash_variable_dummy(1, false); //Get required config, and set them to PSRAM related registers s_do_tuning(reference_data, &timing_configs, false);/* ... */ #endif //#if SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY #if SOC_MEMSPI_TIMING_TUNING_BY_DQS bool is_flash = false; mspi_timing_config_t timing_configs = {}; //Phase mspi_tuning_cfg_drv_t drv = { .psram_tuning_type = MSPI_TIMING_TUNING_MSPI_DQS_PHASE, .sweep_test_nums = 1, .psram_init_mspi = mspi_timing_psram_init, .psram_tune_mspi = mspi_timing_config_psram_set_tuning_phase, .psram_read = mspi_timing_config_psram_read_data, .psram_select_best_tuning_config = mspi_timing_psram_select_best_tuning_phase, .psram_set_best_tuning_config = mspi_timing_psram_set_best_tuning_phase, }{...}; s_register_config_driver(&drv, is_flash); mspi_timing_get_psram_tuning_phases(&timing_configs); s_do_tuning(reference_data, &timing_configs, false); //Delayline drv = (mspi_tuning_cfg_drv_t) { .psram_tuning_type = MSPI_TIMING_TUNING_MSPI_DELAYLINE, .sweep_test_nums = MSPI_TIMING_DELAYLINE_TEST_NUMS, .psram_init_mspi = mspi_timing_psram_init, .psram_tune_mspi = mspi_timing_config_psram_set_tuning_delayline, .psram_read = mspi_timing_config_psram_read_data, .psram_select_best_tuning_config = mspi_timing_psram_select_best_tuning_delayline, .psram_set_best_tuning_config = mspi_timing_psram_set_best_tuning_delayline, }{...}; s_register_config_driver(&drv, is_flash); mspi_timing_get_psram_tuning_delaylines(&timing_configs); s_do_tuning(reference_data, &timing_configs, false);/* ... */ #endif mspi_timing_enter_high_speed_mode(true); }{...} /* ... */ #else void mspi_timing_psram_tuning(void) { //Empty function for compatibility, therefore upper layer won't need to know that FLASH in which operation mode and frequency config needs to be tuned }{ ... } /* ... */#endif //MSPI_TIMING_PSRAM_NEEDS_TUNING /*------------------------------------------------------------------------------ * APIs to make SPI0 (and SPI1) FLASH work for high/low freq *----------------------------------------------------------------------------*//* ... */ void mspi_timing_enter_low_speed_mode(bool control_spi1) { #if SOC_MEMSPI_FLASH_CLK_SRC_IS_INDEPENDENT #if CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C61 // TODO: IDF-10464 mspi_ll_clock_src_sel(MSPI_CLK_SRC_XTAL); #else spimem_flash_ll_set_clock_source(MSPI_CLK_SRC_ROM_DEFAULT); #endif/* ... */ #endif //SOC_MEMSPI_FLASH_CLK_SRC_IS_INDEPENDENT #if SOC_SPI_MEM_SUPPORT_TIMING_TUNING /** * Here we are going to slow the SPI1 frequency to 20Mhz, so we need to set SPI1 din_num and din_mode regs. * * Because SPI0 and SPI1 share the din_num and din_mode regs, so if we clear SPI1 din_num and din_mode to * 0, if the SPI0 flash module clock is still in high freq, it may not work correctly. * * Therefore, here we need to slow both the SPI0 and SPI1 and related timing tuning regs to 20Mhz configuration. * * Currently we only need to change these clocks on chips with timing tuning * Should be extended to other no-timing-tuning chips if needed. e.g.: * we still need to turn down Flash / PSRAM clock speed at a certain period of time *//* ... */ mspi_timing_config_set_flash_clock(20, MSPI_TIMING_SPEED_MODE_LOW_PERF, control_spi1); mspi_timing_config_set_psram_clock(20, MSPI_TIMING_SPEED_MODE_LOW_PERF, control_spi1);/* ... */ #endif //#if SOC_SPI_MEM_SUPPORT_TIMING_TUNING #if MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING mspi_timing_flash_config_clear_tuning_regs(control_spi1); mspi_timing_psram_config_clear_tuning_regs(control_spi1);/* ... */ #endif //#if MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING }{ ... } /** * Set FLASH and PSRAM module clock, din_num, din_mode and extra dummy, * according to the configuration got from timing tuning function (`calculate_best_flash_tuning_config`). * iF control_spi1 == 1, will also update SPI1 timing registers. Should only be set to 1 when do tuning. * * This function should always be called after `mspi_timing_flash_tuning` or `calculate_best_flash_tuning_config` *//* ... */ void mspi_timing_enter_high_speed_mode(bool control_spi1) { #if SOC_MEMSPI_FLASH_CLK_SRC_IS_INDEPENDENT #if CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C61// TODO: IDF-10464 mspi_ll_clock_src_sel(MSPI_CLK_SRC_SPLL); #else spimem_flash_ll_set_clock_source(MSPI_CLK_SRC_DEFAULT); #endif/* ... */ #endif //SOC_MEMSPI_FLASH_CLK_SRC_IS_INDEPENDENT #if SOC_SPI_MEM_SUPPORT_TIMING_TUNING /** * Currently we only need to change these clocks on chips with timing tuning * Should be extended to other no-timing-tuning chips if needed. e.g.: * we still need to turn down Flash / PSRAM clock speed at a certain period of time *//* ... */ mspi_timing_config_set_flash_clock(FLASH_FREQUENCY_MHZ, MSPI_TIMING_SPEED_MODE_NORMAL_PERF, control_spi1); #if CONFIG_SPIRAM mspi_timing_config_set_psram_clock(CONFIG_SPIRAM_SPEED, MSPI_TIMING_SPEED_MODE_NORMAL_PERF, control_spi1); #endif //#if CONFIG_SPIRAM/* ... */ #endif //#if SOC_SPI_MEM_SUPPORT_TIMING_TUNING #if MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING mspi_timing_flash_config_set_tuning_regs(control_spi1); mspi_timing_psram_config_set_tuning_regs(control_spi1);/* ... */ #endif //#if MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING }{ ... } void mspi_timing_change_speed_mode_cache_safe(bool switch_down) { #if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE && !CONFIG_FREERTOS_UNICORE // For esp chips with two levels of Cache, if another core attempts to access SPI Flash or PSRAM after the // cache is freeze, the access will fail and will keep retrying. This will completely block the L1 Cache, // causing the current core to be unable to access the stack and data in the L2 RAM, which will causes a // deadlock, so we need to stall another core at first. esp_ipc_isr_stall_other_cpu();/* ... */ #endif /** * If a no-cache-freeze-supported chip needs timing tuning, add a protection way: * - spinlock * - or other way * * for preventing concurrent from MSPI to external memory *//* ... */ #if SOC_CACHE_FREEZE_SUPPORTED cache_hal_freeze(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL); #endif //#if SOC_CACHE_FREEZE_SUPPORTED if (switch_down) { //enter MSPI low speed mode, extra delays should be removed mspi_timing_enter_low_speed_mode(false); }{...} else { //enter MSPI high speed mode, extra delays should be considered mspi_timing_enter_high_speed_mode(false); }{...} #if SOC_CACHE_FREEZE_SUPPORTED cache_hal_unfreeze(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL); #endif //#if SOC_CACHE_FREEZE_SUPPORTED #if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE && !CONFIG_FREERTOS_UNICORE esp_ipc_isr_release_other_cpu(); #endif }{ ... } /*------------------------------------------------------------------------------ * APIs to inform SPI1 Flash driver of necessary timing configurations *----------------------------------------------------------------------------*//* ... */ bool spi_flash_timing_is_tuned(void) { #if MSPI_TIMING_MSPI1_IS_INVOLVED //esp flash driver needs to be notified #if MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING //either flash or psram or both is tuned, needs notify flash driver return true;/* ... */ #else //otherwise no need return false;/* ... */ #endif/* ... */ #else //if mspi1 is not involved in timing tuning return false;/* ... */ #endif //MSPI_TIMING_MSPI1_IS_INVOLVED }{ ... } #if MSPI_TIMING_MSPI1_IS_INVOLVED && (MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING) void spi_timing_get_flash_timing_param(spi_flash_hal_timing_config_t *out_timing_config) { // Get clock configuration directly from system. out_timing_config->clock_config.spimem = mspi_timing_config_get_flash_clock_reg(); // Get extra dummy length here. Therefore, no matter what freq, or mode. // If it needs tuning, it will return correct extra dummy len. If no tuning, it will return 0. out_timing_config->extra_dummy = mspi_timing_config_get_flash_extra_dummy(); // Get CS setup/hold value here. mspi_timing_config_get_cs_timing(&out_timing_config->cs_setup, &out_timing_config->cs_hold); }{...} /* ... */#else void spi_timing_get_flash_timing_param(spi_flash_hal_timing_config_t *out_timing_config) { // This function shouldn't be called if timing tuning is not used. abort(); }{ ... } /* ... */#endif // #if MSPI_TIMING_MSPI1_IS_INVOLVED && (MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING) /*------------------------------------------------------------------------------ * Common settings *----------------------------------------------------------------------------*//* ... */ void mspi_timing_set_pin_drive_strength(void) { #if SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY //For now, set them all to 3. Need to check after QVL test results are out. TODO: IDF-3663 //Set default pin drive mspi_timing_ll_set_all_pin_drive(0, 3);/* ... */ #endif // #if SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY }{ ... }
Details
Show:
from
Types: Columns:
This file uses the notable symbols shown below. Click anywhere in the file to view more details.