mspi_timing_tuning.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537
  1. /*
  2. * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include "sdkconfig.h"
  9. #include "esp_attr.h"
  10. #include "esp_err.h"
  11. #include "esp_types.h"
  12. #include "esp_log.h"
  13. #include "soc/io_mux_reg.h"
  14. #include "soc/soc.h"
  15. #include "hal/spi_flash_hal.h"
  16. #include "hal/cache_hal.h"
  17. #include "hal/cache_ll.h"
  18. #include "esp_private/mspi_timing_tuning.h"
  19. #include "mspi_timing_config.h"
  20. #include "mspi_timing_by_mspi_delay.h"
  21. #if SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY
  22. #include "mspi_timing_tuning_configs.h"
  23. #include "hal/mspi_timing_tuning_ll.h"
  24. #endif
  25. #if SOC_MEMSPI_CLK_SRC_IS_INDEPENDENT
  26. #include "hal/spimem_flash_ll.h"
  27. #endif
  28. #if CONFIG_ESPTOOLPY_FLASHFREQ_120M
  29. #define FLASH_FREQUENCY_MHZ 120
  30. #elif CONFIG_ESPTOOLPY_FLASHFREQ_80M
  31. #define FLASH_FREQUENCY_MHZ 80
  32. #elif CONFIG_ESPTOOLPY_FLASHFREQ_64M
  33. #define FLASH_FREQUENCY_MHZ 64
  34. #elif CONFIG_ESPTOOLPY_FLASHFREQ_60M
  35. #define FLASH_FREQUENCY_MHZ 60
  36. #elif CONFIG_ESPTOOLPY_FLASHFREQ_48M
  37. #define FLASH_FREQUENCY_MHZ 48
  38. #elif CONFIG_ESPTOOLPY_FLASHFREQ_40M
  39. #define FLASH_FREQUENCY_MHZ 40
  40. #elif CONFIG_ESPTOOLPY_FLASHFREQ_32M
  41. #define FLASH_FREQUENCY_MHZ 32
  42. #elif CONFIG_ESPTOOLPY_FLASHFREQ_30M
  43. #define FLASH_FREQUENCY_MHZ 30
  44. #elif CONFIG_ESPTOOLPY_FLASHFREQ_26M
  45. #define FLASH_FREQUENCY_MHZ 26
  46. #elif CONFIG_ESPTOOLPY_FLASHFREQ_24M
  47. #define FLASH_FREQUENCY_MHZ 24
  48. #elif CONFIG_ESPTOOLPY_FLASHFREQ_20M
  49. #define FLASH_FREQUENCY_MHZ 20
  50. #elif CONFIG_ESPTOOLPY_FLASHFREQ_16M
  51. #define FLASH_FREQUENCY_MHZ 16
  52. #elif CONFIG_ESPTOOLPY_FLASHFREQ_15M
  53. #define FLASH_FREQUENCY_MHZ 15
  54. #endif
  55. /**
  56. * @brief MSPI timing tuning type
  57. */
  58. typedef enum {
  59. MSPI_TIMING_TUNING_MSPI_DIN_DUMMY, //tune by mspi din and dummy
  60. } mspi_timing_tuning_t;
  61. typedef struct mspi_tuning_cfg_drv_s mspi_tuning_cfg_drv_t;
  62. __attribute__((unused)) const static char *TAG = "MSPI Timing";
  63. struct mspi_tuning_cfg_drv_s {
  64. /**
  65. * @brief Flash tuning scheme type
  66. */
  67. mspi_timing_tuning_t flash_tuning_type;
  68. /**
  69. * @brief Init MSPI for Flash timing tuning
  70. *
  71. * @param[in] flash_freq_mhz Flash frequency in MHz
  72. */
  73. void (*flash_init_mspi)(uint32_t flash_freq_mhz);
  74. /**
  75. * @brief Configure MSPI for Flash timing tuning
  76. *
  77. * @param[in] params Timing tuning parameters
  78. */
  79. void (*flash_tune_mspi)(const void *params);
  80. /**
  81. * @brief Flash read
  82. *
  83. * @param[in] buf Read buffer
  84. * @param[in] addr Read address
  85. * @param[in] len Read length
  86. */
  87. void (*flash_read)(uint8_t *buf, uint32_t addr, uint32_t len);
  88. /**
  89. * @brief Select best tuning configs for Flash
  90. *
  91. * @param[in] configs Timing tuning configurations
  92. * @param[in] consecutive_length Length of the consecutive successful sample results
  93. * @param[in] end End of the consecutive successful sample results
  94. * @param[in] reference_data Reference data
  95. * @param[in] is_ddr DDR or SDR
  96. *
  97. * @return Best config ID
  98. */
  99. 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);
  100. /**
  101. * @brief Set best Flash tuning configs.
  102. * After this, calling `mspi_timing_enter_high_speed_mode` will set these configs correctly
  103. *
  104. * @param[in] params Timing tuning parameters
  105. */
  106. void (*flash_set_best_tuning_config)(const void *params);
  107. /**
  108. * @brief PSRAM tuning scheme type
  109. */
  110. mspi_timing_tuning_t psram_tuning_type;
  111. /**
  112. * @brief Init MSPI for PSRAM timing tuning
  113. *
  114. * @param[in] flash_freq_mhz PSRAM frequency in MHz
  115. */
  116. void (*psram_init_mspi)(uint32_t psram_freq_mhz);
  117. /**
  118. * @brief Configure MSPI for PSRAM timing tuning
  119. *
  120. * @param[in] params Timing tuning parameters
  121. */
  122. void (*psram_tune_mspi)(const void *params);
  123. /**
  124. * @brief PSRAM read
  125. *
  126. * @param[in] buf Read buffer
  127. * @param[in] addr Read address
  128. * @param[in] len Read length
  129. */
  130. void (*psram_read)(uint8_t *buf, uint32_t addr, uint32_t len);
  131. /**
  132. * @brief Select best tuning configs for PSRAM
  133. *
  134. * @param[in] configs Timing tuning configurations
  135. * @param[in] consecutive_length Length of the consecutive successful sample results
  136. * @param[in] end End of the consecutive successful sample results
  137. * @param[in] reference_data Reference data
  138. * @param[in] is_ddr DDR or SDR
  139. *
  140. * @return Best config ID
  141. */
  142. 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);
  143. /**
  144. * @brief Set best PSRAM tuning configs.
  145. * After this, calling `mspi_timing_enter_high_speed_mode` will set these configs correctly
  146. *
  147. * @param[in] params Timing tuning parameters
  148. */
  149. void (*psram_set_best_tuning_config)(const void *params);
  150. };
  151. static mspi_tuning_cfg_drv_t s_tuning_cfg_drv = {};
  152. void s_register_config_driver(mspi_tuning_cfg_drv_t *cfg_drv, bool is_flash)
  153. {
  154. if (is_flash) {
  155. s_tuning_cfg_drv.flash_tuning_type = cfg_drv->flash_tuning_type;
  156. s_tuning_cfg_drv.flash_init_mspi = cfg_drv->flash_init_mspi;
  157. s_tuning_cfg_drv.flash_tune_mspi = cfg_drv->flash_tune_mspi;
  158. s_tuning_cfg_drv.flash_read = cfg_drv->flash_read;
  159. s_tuning_cfg_drv.flash_select_best_tuning_config = cfg_drv->flash_select_best_tuning_config;
  160. s_tuning_cfg_drv.flash_set_best_tuning_config = cfg_drv->flash_set_best_tuning_config;
  161. } else {
  162. s_tuning_cfg_drv.psram_tuning_type = cfg_drv->psram_tuning_type;
  163. s_tuning_cfg_drv.psram_init_mspi = cfg_drv->psram_init_mspi;
  164. s_tuning_cfg_drv.psram_tune_mspi = cfg_drv->psram_tune_mspi;
  165. s_tuning_cfg_drv.psram_read = cfg_drv->psram_read;
  166. s_tuning_cfg_drv.psram_select_best_tuning_config = cfg_drv->psram_select_best_tuning_config;
  167. s_tuning_cfg_drv.psram_set_best_tuning_config = cfg_drv->psram_set_best_tuning_config;
  168. }
  169. }
  170. #if MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING
  171. /**
  172. * We use different MSPI timing tuning config to read data to see if current MSPI sampling is successful.
  173. * The sampling result will be stored in an array. In this array, successful item will be 1, failed item will be 0.
  174. */
  175. static void s_sweep_for_success_sample_points(uint8_t *reference_data, void *config, bool is_flash, uint8_t *out_array)
  176. {
  177. const mspi_timing_config_t *timing_config = (const mspi_timing_config_t *)config;
  178. uint32_t config_idx = 0;
  179. uint8_t read_data[MSPI_TIMING_TEST_DATA_LEN] = {0};
  180. for (config_idx = 0; config_idx < timing_config->available_config_num; config_idx++) {
  181. memset(read_data, 0, MSPI_TIMING_TEST_DATA_LEN);
  182. #if MSPI_TIMING_FLASH_NEEDS_TUNING
  183. if (is_flash) {
  184. s_tuning_cfg_drv.flash_tune_mspi(&(timing_config->tuning_config_table[config_idx]));
  185. s_tuning_cfg_drv.flash_read(read_data, MSPI_TIMING_FLASH_TEST_DATA_ADDR, sizeof(read_data));
  186. }
  187. #endif
  188. #if MSPI_TIMING_PSRAM_NEEDS_TUNING
  189. if (!is_flash) {
  190. s_tuning_cfg_drv.psram_tune_mspi(&(timing_config->tuning_config_table[config_idx]));
  191. s_tuning_cfg_drv.psram_read(read_data, MSPI_TIMING_PSRAM_TEST_DATA_ADDR, MSPI_TIMING_TEST_DATA_LEN);
  192. }
  193. #endif
  194. if (memcmp(reference_data, read_data, sizeof(read_data)) == 0) {
  195. out_array[config_idx] = 1;
  196. ESP_EARLY_LOGD(TAG, "%"PRIu32", good", config_idx);
  197. } else {
  198. ESP_EARLY_LOGD(TAG, "%"PRIu32", bad", config_idx);
  199. }
  200. }
  201. }
  202. /**
  203. * Find consecutive successful sampling points.
  204. * e.g. array: {1, 1, 0, 0, 1, 1, 1, 0}
  205. * out_length: 3
  206. * outout_end_index: 6
  207. */
  208. static void s_find_max_consecutive_success_points(uint8_t *array, uint32_t size, uint32_t *out_length, uint32_t *out_end_index)
  209. {
  210. uint32_t max = 0;
  211. uint32_t match_num = 0;
  212. uint32_t i = 0;
  213. uint32_t end = 0;
  214. while (i < size) {
  215. if (array[i]) {
  216. match_num++;
  217. } else {
  218. if (match_num > max) {
  219. max = match_num;
  220. end = i - 1;
  221. }
  222. match_num = 0;
  223. }
  224. i++;
  225. }
  226. *out_length = match_num > max ? match_num : max;
  227. *out_end_index = match_num == size ? size : end;
  228. }
  229. 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)
  230. {
  231. const mspi_timing_config_t *timing_config = (const mspi_timing_config_t *)config;
  232. uint32_t best_point = 0;
  233. if (is_flash) {
  234. #if MSPI_TIMING_FLASH_DTR_MODE
  235. best_point = s_tuning_cfg_drv.flash_select_best_tuning_config(timing_config, consecutive_length, end, reference_data, IS_DDR);
  236. #elif MSPI_TIMING_FLASH_STR_MODE
  237. best_point = s_tuning_cfg_drv.flash_select_best_tuning_config(timing_config, consecutive_length, end, NULL, IS_SDR);
  238. #endif
  239. s_tuning_cfg_drv.flash_set_best_tuning_config(&(timing_config->tuning_config_table[best_point]));
  240. } else {
  241. #if MSPI_TIMING_PSRAM_DTR_MODE
  242. best_point = s_tuning_cfg_drv.psram_select_best_tuning_config(timing_config, consecutive_length, end, reference_data, IS_DDR);
  243. #elif MSPI_TIMING_PSRAM_STR_MODE
  244. best_point = s_tuning_cfg_drv.psram_select_best_tuning_config(timing_config, consecutive_length, end, NULL, IS_SDR);
  245. #endif
  246. s_tuning_cfg_drv.psram_set_best_tuning_config(&(timing_config->tuning_config_table[best_point]));
  247. }
  248. }
  249. static void s_do_tuning(uint8_t *reference_data, void *timing_config, bool is_flash)
  250. {
  251. /**
  252. * We use MSPI to tune the timing:
  253. * 1. Get all MSPI sampling results.
  254. * 2. Find the longest consecutive successful sampling points from the result above.
  255. * 3. The middle one will be the best sampling point.
  256. */
  257. uint32_t consecutive_length = 0;
  258. uint32_t last_success_point = 0;
  259. uint8_t sample_result[MSPI_TIMING_CONFIG_NUM_DEFAULT] = {0};
  260. #if MSPI_TIMING_FLASH_NEEDS_TUNING
  261. if (is_flash) {
  262. s_tuning_cfg_drv.flash_init_mspi(FLASH_FREQUENCY_MHZ);
  263. }
  264. #endif
  265. #if MSPI_TIMING_PSRAM_NEEDS_TUNING
  266. if (!is_flash) {
  267. s_tuning_cfg_drv.psram_init_mspi(CONFIG_SPIRAM_SPEED);
  268. }
  269. #endif
  270. s_sweep_for_success_sample_points(reference_data, timing_config, is_flash, sample_result);
  271. s_find_max_consecutive_success_points(sample_result, MSPI_TIMING_CONFIG_NUM_DEFAULT, &consecutive_length, &last_success_point);
  272. s_select_best_tuning_config(timing_config, consecutive_length, last_success_point, reference_data, is_flash);
  273. }
  274. #endif //#if MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING
  275. /*------------------------------------------------------------------------------
  276. * FLASH Timing Tuning
  277. *----------------------------------------------------------------------------*/
  278. #if MSPI_TIMING_FLASH_NEEDS_TUNING
  279. void mspi_timing_flash_tuning(void)
  280. {
  281. /**
  282. * set MSPI related regs to 20mhz configuration, to get reference data from FLASH
  283. * see detailed comments in this function (`mspi_timing_enter_low_speed_mode`)
  284. */
  285. mspi_timing_enter_low_speed_mode(true);
  286. #if SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY
  287. mspi_tuning_cfg_drv_t drv = {
  288. .flash_tuning_type = MSPI_TIMING_TUNING_MSPI_DIN_DUMMY,
  289. .flash_init_mspi = mspi_timing_flash_init,
  290. .flash_tune_mspi = mspi_timing_config_flash_set_tuning_regs,
  291. .flash_read = mspi_timing_config_flash_read_data,
  292. .flash_select_best_tuning_config = mspi_timing_flash_select_best_tuning_config,
  293. .flash_set_best_tuning_config = mspi_timing_flash_set_best_tuning_config,
  294. };
  295. bool is_flash = true;
  296. s_register_config_driver(&drv, is_flash);
  297. //Disable the variable dummy mode when doing timing tuning
  298. mspi_timing_ll_enable_flash_variable_dummy(1, false); //GD flash will read error in variable mode with 20MHz
  299. uint8_t reference_data[MSPI_TIMING_TEST_DATA_LEN] = {0};
  300. s_tuning_cfg_drv.flash_read(reference_data, MSPI_TIMING_FLASH_TEST_DATA_ADDR, sizeof(reference_data));
  301. mspi_timing_config_t timing_configs = {0};
  302. mspi_timing_get_flash_tuning_configs(&timing_configs);
  303. #endif //SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY
  304. s_do_tuning(reference_data, &timing_configs, true);
  305. mspi_timing_enter_high_speed_mode(true);
  306. }
  307. #else
  308. void mspi_timing_flash_tuning(void)
  309. {
  310. //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
  311. }
  312. #endif //MSPI_TIMING_FLASH_NEEDS_TUNING
  313. /*------------------------------------------------------------------------------
  314. * PSRAM Timing Tuning
  315. *----------------------------------------------------------------------------*/
  316. #if MSPI_TIMING_PSRAM_NEEDS_TUNING
  317. void mspi_timing_psram_tuning(void)
  318. {
  319. /**
  320. * set MSPI related regs to 20mhz configuration, to write reference data to PSRAM
  321. * see detailed comments in this function (`mspi_timing_enter_low_speed_mode`)
  322. */
  323. mspi_timing_enter_low_speed_mode(true);
  324. #if SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY
  325. // write data into psram, used to do timing tuning test.
  326. uint8_t reference_data[MSPI_TIMING_TEST_DATA_LEN];
  327. for (int i=0; i < MSPI_TIMING_TEST_DATA_LEN/4; i++) {
  328. ((uint32_t *)reference_data)[i] = 0xa5ff005a;
  329. }
  330. mspi_timing_config_psram_write_data(reference_data, MSPI_TIMING_PSRAM_TEST_DATA_ADDR, MSPI_TIMING_TEST_DATA_LEN);
  331. mspi_tuning_cfg_drv_t drv = {
  332. .psram_tuning_type = MSPI_TIMING_TUNING_MSPI_DIN_DUMMY,
  333. .psram_init_mspi = mspi_timing_psram_init,
  334. .psram_tune_mspi = mspi_timing_config_psram_set_tuning_regs,
  335. .psram_read = mspi_timing_config_psram_read_data,
  336. .psram_select_best_tuning_config = mspi_timing_psram_select_best_tuning_config,
  337. .psram_set_best_tuning_config = mspi_timing_psram_set_best_tuning_config,
  338. };
  339. bool is_flash = false;
  340. s_register_config_driver(&drv, is_flash);
  341. mspi_timing_config_t timing_configs = {0};
  342. mspi_timing_get_psram_tuning_configs(&timing_configs);
  343. #endif //#if SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY
  344. //Disable the variable dummy mode when doing timing tuning
  345. mspi_timing_ll_enable_flash_variable_dummy(1, false);
  346. //Get required config, and set them to PSRAM related registers
  347. s_do_tuning(reference_data, &timing_configs, false);
  348. mspi_timing_enter_high_speed_mode(true);
  349. }
  350. #else
  351. void mspi_timing_psram_tuning(void)
  352. {
  353. //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
  354. }
  355. #endif //MSPI_TIMING_PSRAM_NEEDS_TUNING
  356. /*------------------------------------------------------------------------------
  357. * APIs to make SPI0 (and SPI1) FLASH work for high/low freq
  358. *----------------------------------------------------------------------------*/
  359. void mspi_timing_enter_low_speed_mode(bool control_spi1)
  360. {
  361. #if SOC_MEMSPI_FLASH_CLK_SRC_IS_INDEPENDENT
  362. spimem_flash_ll_set_clock_source(MSPI_CLK_SRC_ROM_DEFAULT);
  363. #endif //SOC_MEMSPI_FLASH_CLK_SRC_IS_INDEPENDENT
  364. #if SOC_SPI_MEM_SUPPORT_TIMING_TUNING
  365. /**
  366. * Here we are going to slow the SPI1 frequency to 20Mhz, so we need to set SPI1 din_num and din_mode regs.
  367. *
  368. * Because SPI0 and SPI1 share the din_num and din_mode regs, so if we clear SPI1 din_num and din_mode to
  369. * 0, if the SPI0 flash module clock is still in high freq, it may not work correctly.
  370. *
  371. * Therefore, here we need to slow both the SPI0 and SPI1 and related timing tuning regs to 20Mhz configuration.
  372. *
  373. * Currently we only need to change these clocks on chips with timing tuning
  374. * Should be extended to other no-timing-tuning chips if needed. e.g.:
  375. * we still need to turn down Flash / PSRAM clock speed at a certain period of time
  376. */
  377. mspi_timing_config_set_flash_clock(20, MSPI_TIMING_SPEED_MODE_LOW_PERF, control_spi1);
  378. mspi_timing_config_set_psram_clock(20, MSPI_TIMING_SPEED_MODE_LOW_PERF, control_spi1);
  379. #endif //#if SOC_SPI_MEM_SUPPORT_TIMING_TUNING
  380. #if MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING
  381. mspi_timing_flash_config_clear_tuning_regs(control_spi1);
  382. mspi_timing_psram_config_clear_tuning_regs(control_spi1);
  383. #endif //#if MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING
  384. }
  385. /**
  386. * Set FLASH and PSRAM module clock, din_num, din_mode and extra dummy,
  387. * according to the configuration got from timing tuning function (`calculate_best_flash_tuning_config`).
  388. * iF control_spi1 == 1, will also update SPI1 timing registers. Should only be set to 1 when do tuning.
  389. *
  390. * This function should always be called after `mspi_timing_flash_tuning` or `calculate_best_flash_tuning_config`
  391. */
  392. void mspi_timing_enter_high_speed_mode(bool control_spi1)
  393. {
  394. #if SOC_MEMSPI_FLASH_CLK_SRC_IS_INDEPENDENT
  395. spimem_flash_ll_set_clock_source(MSPI_CLK_SRC_DEFAULT);
  396. #endif //SOC_MEMSPI_FLASH_CLK_SRC_IS_INDEPENDENT
  397. #if SOC_SPI_MEM_SUPPORT_TIMING_TUNING
  398. /**
  399. * Currently we only need to change these clocks on chips with timing tuning
  400. * Should be extended to other no-timing-tuning chips if needed. e.g.:
  401. * we still need to turn down Flash / PSRAM clock speed at a certain period of time
  402. */
  403. mspi_timing_config_set_flash_clock(FLASH_FREQUENCY_MHZ, MSPI_TIMING_SPEED_MODE_NORMAL_PERF, control_spi1);
  404. #if CONFIG_SPIRAM
  405. mspi_timing_config_set_psram_clock(CONFIG_SPIRAM_SPEED, MSPI_TIMING_SPEED_MODE_NORMAL_PERF, control_spi1);
  406. #endif //#if CONFIG_SPIRAM
  407. #endif //#if SOC_SPI_MEM_SUPPORT_TIMING_TUNING
  408. #if MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING
  409. mspi_timing_flash_config_set_tuning_regs(control_spi1);
  410. mspi_timing_psram_config_set_tuning_regs(control_spi1);
  411. #endif //#if MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING
  412. }
  413. void mspi_timing_change_speed_mode_cache_safe(bool switch_down)
  414. {
  415. /**
  416. * If a no-cache-freeze-supported chip needs timing tuning, add a protection way:
  417. * - spinlock
  418. * - or other way
  419. *
  420. * for preventing concurrent from MSPI to external memory
  421. */
  422. #if SOC_CACHE_FREEZE_SUPPORTED
  423. cache_hal_freeze(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
  424. #endif //#if SOC_CACHE_FREEZE_SUPPORTED
  425. if (switch_down) {
  426. //enter MSPI low speed mode, extra delays should be removed
  427. mspi_timing_enter_low_speed_mode(false);
  428. } else {
  429. //enter MSPI high speed mode, extra delays should be considered
  430. mspi_timing_enter_high_speed_mode(false);
  431. }
  432. #if SOC_CACHE_FREEZE_SUPPORTED
  433. cache_hal_unfreeze(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_ALL);
  434. #endif //#if SOC_CACHE_FREEZE_SUPPORTED
  435. }
  436. /*------------------------------------------------------------------------------
  437. * APIs to inform SPI1 Flash driver of necessary timing configurations
  438. *----------------------------------------------------------------------------*/
  439. bool spi_timing_is_tuned(void)
  440. {
  441. #if MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING
  442. return true;
  443. #else
  444. return false;
  445. #endif
  446. }
  447. #if MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING
  448. void spi_timing_get_flash_timing_param(spi_flash_hal_timing_config_t *out_timing_config)
  449. {
  450. // Get clock configuration directly from system.
  451. out_timing_config->clock_config.spimem = mspi_timing_config_get_flash_clock_reg();
  452. // Get extra dummy length here. Therefore, no matter what freq, or mode.
  453. // If it needs tuning, it will return correct extra dummy len. If no tuning, it will return 0.
  454. out_timing_config->extra_dummy = mspi_timing_config_get_flash_extra_dummy();
  455. // Get CS setup/hold value here.
  456. mspi_timing_config_get_cs_timing(&out_timing_config->cs_setup, &out_timing_config->cs_hold);
  457. }
  458. #else
  459. void spi_timing_get_flash_timing_param(spi_flash_hal_timing_config_t *out_timing_config)
  460. {
  461. // This function shouldn't be called if timing tuning is not used.
  462. abort();
  463. }
  464. #endif // MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING
  465. /*------------------------------------------------------------------------------
  466. * Common settings
  467. *----------------------------------------------------------------------------*/
  468. void mspi_timing_set_pin_drive_strength(void)
  469. {
  470. #if SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY
  471. //For now, set them all to 3. Need to check after QVL test results are out. TODO: IDF-3663
  472. //Set default pin drive
  473. mspi_timing_ll_set_all_pin_drive(0, 3);
  474. #endif // #if SOC_MEMSPI_TIMING_TUNING_BY_MSPI_DELAY
  475. }