cwespressif commented on code in PR #10625:
URL: https://github.com/apache/nuttx/pull/10625#discussion_r1325843113
##########
arch/xtensa/src/esp32s3/esp32s3_spi_timing.c:
##########
@@ -238,129 +349,1232 @@ static void IRAM_ATTR set_flash_clock(uint8_t spi_num,
uint32_t freqdiv)
}
}
+#if ESP32S3_SPI_TIMING_FLASH_TUNING || ESP32S3_SPI_TIMING_PSRAM_TUNING
+
/****************************************************************************
- * Public Functions
+ * Name: init_spi1_for_tuning
+ *
+ * Description:
+ * Initialize SPI1 for timing tuning.
+ *
+ * Input Parameters:
+ * is_flash - is flash or not
+ *
+ * Returned Value:
+ * None.
+ *
****************************************************************************/
+static void init_spi1_for_tuning(bool is_flash)
+{
+ /* Set SPI1 core clock. SPI0 and SPI1 share the register for core clock.
+ * So we only set SPI0 here.
+ */
+
+ REG_SET_FIELD(SPI_MEM_CORE_CLK_SEL_REG(0),
+ SPI_MEM_CORE_CLK_SEL,
+ DEFAULT_CORE_CLK_REG);
+
+ /* Set SPI1 module clock as required */
+
+ if (is_flash)
+ {
+ set_flash_clock(1, FLASH_CLOCK_DIVIDER);
+
+ /* Enable Flash HCLK */
+
+ REG_SET_BIT(SPI_MEM_TIMING_CALI_REG(0), SPI_MEM_TIMING_CLK_ENA);
+ }
+ else
+ {
+ /* We use SPI1 Flash to tune PSRAM, PSRAM timing related regs
+ * do nothing on SPI1
+ */
+
+ set_flash_clock(1, PSRAM_CLOCK_DIVIDER);
+
+ /* Enable PSRAM HCLK */
+
+ REG_SET_BIT(SPI_MEM_SPI_SMEM_TIMING_CALI_REG(0),
+ SPI_MEM_SPI_SMEM_TIMING_CLK_ENA);
+ }
+}
+
/****************************************************************************
- * Name: esp32s3_spi_timing_set_pin_drive_strength
+ * Name: get_dummy
*
* Description:
- * Make SPI all GPIO strength to be 3 under default clock.
+ * Get dummy cycle length
*
* Input Parameters:
* None
*
* Returned Value:
+ * Dummy cycle length.
+ *
+ ****************************************************************************/
+
+static uint32_t get_dummy(void)
+{
+ uint32_t ctrl_reg = READ_PERI_REG(SPI_MEM_CTRL_REG(0));
+ if (ctrl_reg & MSPI_TIMING_LL_FLASH_OCT_MASK)
+ {
+ DEBUGASSERT(0);
+ return 0;
+ }
+
+#if ESP32S3_SPI_FLASH_HPM_ENABLE
+ /* HPM is not enabled */
+
+ DEBUGASSERT();
+ return 0;
+#endif
+ switch (ctrl_reg & MSPI_TIMING_LL_FLASH_QUAD_MASK)
+ {
+ case MSPI_TIMING_LL_FLASH_QIO_MODE_MASK:
+ return SPI1_R_QIO_DUMMY_CYCLELEN;
+ case MSPI_TIMING_LL_FLASH_DIO_MODE_MASK:
+ return SPI1_R_DIO_DUMMY_CYCLELEN;
+ case MSPI_TIMING_LL_FLASH_QUAD_MODE_MASK:
+ case MSPI_TIMING_LL_FLASH_DUAL_MODE_MASK:
+ case MSPI_TIMING_LL_FLASH_FAST_MODE_MASK:
+ return SPI1_R_FAST_DUMMY_CYCLELEN;
+ default:
+ DEBUGASSERT(0);
+ return 0;
+ }
+}
+
+/****************************************************************************
+ * Name: set_flash_extra_dummy
+ *
+ * Description:
+ * Set MSPI Flash extra dummy
+ *
+ * Input Parameters:
+ * spi_num - SPI0 / 1
+ * extra_dummy - extra dummy
+ *
+ * Returned Value:
* None.
*
****************************************************************************/
-void esp32s3_spi_timing_set_pin_drive_strength(void)
+static void set_flash_extra_dummy(uint8_t spi_num, uint8_t extra_dummy)
{
- const uint32_t regs[] =
+#ifdef CONFIG_ESP32S3_FLASH_MODE_OCT
+ if (extra_dummy > 0)
{
- IO_MUX_GPIO27_REG,
- IO_MUX_GPIO28_REG,
- IO_MUX_GPIO31_REG,
- IO_MUX_GPIO32_REG,
- IO_MUX_GPIO33_REG,
- IO_MUX_GPIO34_REG,
- IO_MUX_GPIO35_REG,
- IO_MUX_GPIO36_REG,
- IO_MUX_GPIO37_REG
- };
+ SET_PERI_REG_MASK(SPI_MEM_TIMING_CALI_REG(spi_num),
+ SPI_MEM_TIMING_CALI_M);
+ SET_PERI_REG_BITS(SPI_MEM_TIMING_CALI_REG(spi_num),
+ SPI_MEM_EXTRA_DUMMY_CYCLELEN_V,
+ extra_dummy,
+ SPI_MEM_EXTRA_DUMMY_CYCLELEN_S);
+ }
+ else
+ {
+ CLEAR_PERI_REG_MASK(SPI_MEM_TIMING_CALI_REG(spi_num),
+ SPI_MEM_TIMING_CALI_M);
+ SET_PERI_REG_BITS(SPI_MEM_TIMING_CALI_REG(spi_num),
+ SPI_MEM_EXTRA_DUMMY_CYCLELEN_V, 0,
+ SPI_MEM_EXTRA_DUMMY_CYCLELEN_S);
+ }
- /* Set default clock */
+ return;
+#endif
+ if (g_flash_extra_dummy[spi_num] == NOT_INIT_INT)
+ {
+ g_flash_extra_dummy[spi_num] = g_spiflash_dummy_len_plus[spi_num];
+ }
- SET_PERI_REG_MASK(SPI_MEM_DATE_REG(0), SPI_MEM_SPICLK_PAD_DRV_CTL_EN);
- REG_SET_FIELD(SPI_MEM_DATE_REG(0), SPI_MEM_SPI_SMEM_SPICLK_FUN_DRV, 3);
- REG_SET_FIELD(SPI_MEM_DATE_REG(0), SPI_MEM_SPI_FMEM_SPICLK_FUN_DRV, 3);
+ g_spiflash_dummy_len_plus[spi_num] = g_flash_extra_dummy[(int)spi_num] +
+ extra_dummy;
- /* Set default mspi d0 ~ d7, dqs pin drive strength */
+ /* Only Quad Flash will run into this branch. */
- for (int i = 0; i < nitems(regs); i++)
+ uint32_t dummy = get_dummy();
+
+ /* Set MSPI Quad Flash dummy */
+
+ SET_PERI_REG_MASK(SPI_MEM_USER_REG(spi_num), SPI_MEM_USR_DUMMY);
+ SET_PERI_REG_BITS(SPI_MEM_USER1_REG(spi_num), SPI_MEM_USR_DUMMY_CYCLELEN_V,
+ dummy + g_spiflash_dummy_len_plus[spi_num], SPI_MEM_USR_DUMMY_CYCLELEN_S);
+}
+
+/****************************************************************************
+ * Name: set_psram_extra_dummy
+ *
+ * Description:
+ * Set MSPI PSRAM extra dummy
+ *
+ * Input Parameters:
+ * spi_num - SPI0 / 1
+ * extra_dummy - extra dummy
+ *
+ * Returned Value:
+ * None.
+ *
+ ****************************************************************************/
+
+static void set_psram_extra_dummy(uint8_t spi_num, uint8_t extra_dummy)
+{
+#if CONFIG_ESP32S3_SPIRAM_MODE_OCT
+
+ /* Set MSPI Octal PSRAM extra dummy */
+
+ if (extra_dummy > 0)
{
- PIN_SET_DRV(regs[i], 3);
+ SET_PERI_REG_MASK(SPI_MEM_SPI_SMEM_TIMING_CALI_REG(spi_num),
+ SPI_MEM_SPI_SMEM_TIMING_CALI_M);
+ SET_PERI_REG_BITS(SPI_MEM_SPI_SMEM_TIMING_CALI_REG(spi_num),
+ SPI_MEM_SPI_SMEM_EXTRA_DUMMY_CYCLELEN_V,
+ extra_dummy,
+ SPI_MEM_SPI_SMEM_EXTRA_DUMMY_CYCLELEN_S);
+ }
+ else
+ {
+ CLEAR_PERI_REG_MASK(SPI_MEM_SPI_SMEM_TIMING_CALI_REG(spi_num),
+ SPI_MEM_SPI_SMEM_TIMING_CALI_M);
+ SET_PERI_REG_BITS(SPI_MEM_SPI_SMEM_TIMING_CALI_REG(spi_num),
+ SPI_MEM_SPI_SMEM_EXTRA_DUMMY_CYCLELEN_V, 0,
+ SPI_MEM_SPI_SMEM_EXTRA_DUMMY_CYCLELEN_S);
}
+
+#elif CONFIG_ESP32S3_SPIRAM_MODE_QUAD
+
+ /* Set MSPI QUAD PSRAM dummy.
+ * HW workaround: Use normal dummy register to set extra dummy, the
+ * calibration dedicated extra dummy register doesn't work for quad mode
+ */
+
+ SET_PERI_REG_MASK(SPI_MEM_CACHE_SCTRL_REG(spi_num),
+ SPI_MEM_USR_RD_SRAM_DUMMY_M);
+ SET_PERI_REG_BITS(SPI_MEM_CACHE_SCTRL_REG(spi_num),
+ SPI_MEM_SRAM_RDUMMY_CYCLELEN_V,
+ (QPI_PSRAM_FAST_READ_DUMMY + extra_dummy - 1),
+ SPI_MEM_SRAM_RDUMMY_CYCLELEN_S);
+#endif
}
/****************************************************************************
- * Name: esp32s3_spi_timing_set_mspi_high_speed
+ * Name: set_flash_din_mode_num
*
* Description:
- * Make MSPI work under the frequency as users set, may add certain
- * delays to MSPI RX direction to meet timing requirements.
+ * Set MSPI Flash Din Mode and Din Num
*
* Input Parameters:
- * spi1 - Select whether to control SPI1
+ * spi_num - SPI0 / 1
+ * din_mode - Din mode
+ * din_num - Din num
*
* Returned Value:
* None.
*
****************************************************************************/
-void IRAM_ATTR esp32s3_spi_timing_set_mspi_high_speed(bool spi1)
+static void set_flash_din_mode_num(uint8_t spi_num, uint8_t din_mode,
+ uint8_t din_num)
{
- uint32_t flash_div = FLASH_CLOCK_DIVIDER;
- uint32_t psram_div = PSRAM_CLOCK_DIVIDER;
+ /* Set MSPI Flash din mode */
- /* Set SPI0 & 1 core clock */
+ uint32_t reg_val = (REG_READ(SPI_MEM_DIN_MODE_REG(spi_num)) &
+ (~(SPI_MEM_DIN0_MODE_M | SPI_MEM_DIN1_MODE_M | SPI_MEM_DIN2_MODE_M |
+ SPI_MEM_DIN3_MODE_M | SPI_MEM_DIN4_MODE_M | SPI_MEM_DIN5_MODE_M |
+ SPI_MEM_DIN6_MODE_M | SPI_MEM_DIN7_MODE_M | SPI_MEM_DINS_MODE_M))) |
+ (din_mode << SPI_MEM_DIN0_MODE_S) | (din_mode << SPI_MEM_DIN1_MODE_S) |
+ (din_mode << SPI_MEM_DIN2_MODE_S) | (din_mode << SPI_MEM_DIN3_MODE_S) |
+ (din_mode << SPI_MEM_DIN4_MODE_S) | (din_mode << SPI_MEM_DIN5_MODE_S) |
+ (din_mode << SPI_MEM_DIN6_MODE_S) | (din_mode << SPI_MEM_DIN7_MODE_S) |
+ (din_mode << SPI_MEM_DINS_MODE_S);
+ REG_WRITE(SPI_MEM_DIN_MODE_REG(spi_num), reg_val);
- REG_SET_FIELD(SPI_MEM_CORE_CLK_SEL_REG(0),
- SPI_MEM_CORE_CLK_SEL,
- DEFAULT_CORE_CLK_REG);
+ /* Set MSPI Flash din num */
- set_flash_clock(0, flash_div);
- if (spi1)
+ reg_val = (REG_READ(SPI_MEM_DIN_NUM_REG(spi_num)) &
+ (~(SPI_MEM_DIN0_NUM_M | SPI_MEM_DIN1_NUM_M | SPI_MEM_DIN2_NUM_M |
+ SPI_MEM_DIN3_NUM_M | SPI_MEM_DIN4_NUM_M | SPI_MEM_DIN5_NUM_M |
+ SPI_MEM_DIN6_NUM_M | SPI_MEM_DIN7_NUM_M | SPI_MEM_DINS_NUM_M))) |
+ (din_num << SPI_MEM_DIN0_NUM_S) | (din_num << SPI_MEM_DIN1_NUM_S) |
+ (din_num << SPI_MEM_DIN2_NUM_S) | (din_num << SPI_MEM_DIN3_NUM_S) |
+ (din_num << SPI_MEM_DIN4_NUM_S) | (din_num << SPI_MEM_DIN5_NUM_S) |
+ (din_num << SPI_MEM_DIN6_NUM_S) | (din_num << SPI_MEM_DIN7_NUM_S) |
+ (din_num << SPI_MEM_DINS_NUM_S);
+ REG_WRITE(SPI_MEM_DIN_NUM_REG(spi_num), reg_val);
+}
+
+/****************************************************************************
+ * Name: set_psram_din_mode_num
+ *
+ * Description:
+ * Set MSPI PSRAM Din Mode and Din Num
+ *
+ * Input Parameters:
+ * spi_num - SPI0 / 1
+ * din_mode - Din mode
+ * din_num - Din num
+ *
+ * Returned Value:
+ * None.
+ *
+ ****************************************************************************/
+
+static void set_psram_din_mode_num(uint8_t spi_num, uint8_t din_mode,
+ uint8_t din_num)
+{
+ /* Set MSPI PSRAM din mode */
+
+ uint32_t reg_val = (REG_READ(SPI_MEM_SPI_SMEM_DIN_MODE_REG(spi_num)) &
+ (~(SPI_MEM_SPI_SMEM_DIN0_MODE_M | SPI_MEM_SPI_SMEM_DIN1_MODE_M |
+ SPI_MEM_SPI_SMEM_DIN2_MODE_M | SPI_MEM_SPI_SMEM_DIN3_MODE_M |
+ SPI_MEM_SPI_SMEM_DIN4_MODE_M | SPI_MEM_SPI_SMEM_DIN5_MODE_M |
+ SPI_MEM_SPI_SMEM_DIN6_MODE_M | SPI_MEM_SPI_SMEM_DIN7_MODE_M |
+ SPI_MEM_SPI_SMEM_DINS_MODE_M))) |
+ (din_mode << SPI_MEM_SPI_SMEM_DIN0_MODE_S) |
+ (din_mode << SPI_MEM_SPI_SMEM_DIN1_MODE_S) |
+ (din_mode << SPI_MEM_SPI_SMEM_DIN2_MODE_S) |
+ (din_mode << SPI_MEM_SPI_SMEM_DIN3_MODE_S) |
+ (din_mode << SPI_MEM_SPI_SMEM_DIN4_MODE_S) |
+ (din_mode << SPI_MEM_SPI_SMEM_DIN5_MODE_S) |
+ (din_mode << SPI_MEM_SPI_SMEM_DIN6_MODE_S) |
+ (din_mode << SPI_MEM_SPI_SMEM_DIN7_MODE_S) |
+ (din_mode << SPI_MEM_SPI_SMEM_DINS_MODE_S);
+ REG_WRITE(SPI_MEM_SPI_SMEM_DIN_MODE_REG(spi_num), reg_val);
+
+ /* Set MSPI PSRAM din num */
+
+ reg_val = (REG_READ(SPI_MEM_SPI_SMEM_DIN_NUM_REG(spi_num)) &
+ (~(SPI_MEM_SPI_SMEM_DIN0_NUM_M | SPI_MEM_SPI_SMEM_DIN1_NUM_M |
+ SPI_MEM_SPI_SMEM_DIN2_NUM_M | SPI_MEM_SPI_SMEM_DIN3_NUM_M |
+ SPI_MEM_SPI_SMEM_DIN4_NUM_M | SPI_MEM_SPI_SMEM_DIN5_NUM_M |
+ SPI_MEM_SPI_SMEM_DIN6_NUM_M | SPI_MEM_SPI_SMEM_DIN7_NUM_M |
+ SPI_MEM_SPI_SMEM_DINS_NUM_M))) |
+ (din_num << SPI_MEM_SPI_SMEM_DIN0_NUM_S) |
+ (din_num << SPI_MEM_SPI_SMEM_DIN1_NUM_S) |
+ (din_num << SPI_MEM_SPI_SMEM_DIN2_NUM_S) |
+ (din_num << SPI_MEM_SPI_SMEM_DIN3_NUM_S) |
+ (din_num << SPI_MEM_SPI_SMEM_DIN4_NUM_S) |
+ (din_num << SPI_MEM_SPI_SMEM_DIN5_NUM_S) |
+ (din_num << SPI_MEM_SPI_SMEM_DIN6_NUM_S) |
+ (din_num << SPI_MEM_SPI_SMEM_DIN7_NUM_S) |
+ (din_num << SPI_MEM_SPI_SMEM_DINS_NUM_S);
+ REG_WRITE(SPI_MEM_SPI_SMEM_DIN_NUM_REG(spi_num), reg_val);
+}
+
+#if ESP32S3_SPI_TIMING_FLASH_TUNING
+
+/****************************************************************************
+ * Name: config_flash_read_data
+ *
+ * Description:
+ * Configure Flash to read data via SPI1h
+ *
+ * Input Parameters:
+ * buf - data buffer pointer
+ * addr - target address value
+ * len - data length
+ *
+ * Returned Value:
+ * None.
+ *
+ ****************************************************************************/
+
+static void config_flash_read_data(uint8_t *buf, uint32_t addr, uint32_t len)
+{
+#ifdef CONFIG_ESP32S3_FLASH_MODE_OCT
+ /* Clear MSPI hw fifo */
+
+ for (int i = 0; i < 16; i++)
{
- set_flash_clock(1, flash_div);
+ REG_WRITE(SPI_MEM_W0_REG(1) + i * 4, 0);
}
- set_psram_clock(0, psram_div);
+ esp_rom_opiflash_read_raw(addr, buf, len);
+#else
+ esp_rom_spiflash_read(addr, (uint32_t *)buf, len);
+#endif
}
/****************************************************************************
- * Name: esp32s3_spi_timing_set_mspi_low_speed
+ * Name: config_flash_set_tuning_regs
*
* Description:
- * Make MSPI work under 20MHz and remove the timing tuning required delays.
+ * Tune Flash timing registers for SPI1 accessing Flash
*
* Input Parameters:
- * spi1 - Select whether to control SPI1
+ * params - tuning timing parameters pointer
*
* Returned Value:
* None.
*
****************************************************************************/
-void IRAM_ATTR esp32s3_spi_timing_set_mspi_low_speed(bool spi1)
+static void config_flash_set_tuning_regs(const tuning_param_s *params)
{
- /**
- * Here we are going to set the SPI1 frequency to be 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,
- * but if we clear SPI1 din_num and din_mode to 0 and SPI0 flash
- * module clock is still in high freq, it may not work correctly.
- *
- * Therefore, we need to set both the SPI0 and SPI1 and related
- * timing tuning regs to be 20MHz.
+ /* SPI_MEM_DINx_MODE(1), SPI_MEM_DINx_NUM(1) are meaningless SPI0 and SPI1
+ * share SPI_MEM_DINx_MODE(0), SPI_MEM_DINx_NUM(0) for FLASH timing tuning
+ * We use SPI1 to get the best Flash timing tuning (mode and num) config
*/
- /* Set SPIMEM core clock as 80MHz, and set SPI1 and SPI0 clock
- * to be 20MHz by setting clock division as 4
- */
+ set_flash_din_mode_num(0, params->spi_din_mode, params->spi_din_num);
+ set_flash_extra_dummy(1, params->extra_dummy_len);
+}
- REG_SET_FIELD(SPI_MEM_CORE_CLK_SEL_REG(0),
- SPI_MEM_CORE_CLK_SEL,
- CORE_CLK_REG_SEL_80M);
+/****************************************************************************
+ * Name: get_flash_tuning_configs
+ *
+ * Description:
+ * Get FLASH tuning configuration.
+ *
+ * Input Parameters:
+ * config - tuning timing configuration pointer
+ *
+ * Returned Value:
+ * None.
+ *
+ ****************************************************************************/
- set_flash_clock(0, 4);
- if (spi1)
- {
- /* After tuning, won't touch SPI1 again */
+static void get_flash_tuning_configs(tuning_config_s *config)
+{
+#if MSPI_TIMING_FLASH_DTR_MODE
+# define FLASH_MODE DTR_MODE
+#else
+# define FLASH_MODE STR_MODE
+#endif
- set_flash_clock(1, 4);
+#if CONFIG_ESP32S3_FLASH_FREQ_20M
+ *config = MSPI_TIMING_FLASH_GET_TUNING_CONFIG(
+ ESP32S3_SPI_TIMING_CORE_CLK, 20, FLASH_MODE);
+#elif CONFIG_ESP32S3_FLASH_FREQ_40M
+ *config = MSPI_TIMING_FLASH_GET_TUNING_CONFIG(
+ ESP32S3_SPI_TIMING_CORE_CLK, 40, FLASH_MODE);
+#elif CONFIG_ESP32S3_FLASH_FREQ_80M
+ *config = MSPI_TIMING_FLASH_GET_TUNING_CONFIG(
+ ESP32S3_SPI_TIMING_CORE_CLK, 80, FLASH_MODE);
+#elif CONFIG_ESP32S3_FLASH_FREQ_120M
+ *config = MSPI_TIMING_FLASH_GET_TUNING_CONFIG(
+ ESP32S3_SPI_TIMING_CORE_CLK, 120, FLASH_MODE);
+#endif
+
+#undef FLASH_MODE
+}
+#endif
+
+#if ESP32S3_SPI_TIMING_PSRAM_TUNING
+
+/****************************************************************************
+ * Name: psram_read_data
+ *
+ * Description:
+ * Configure PSRAM to read data via SPI1.
+ *
+ * Input Parameters:
+ * buf - data buffer pointer
+ * addr - target address value
+ * len - data length
+ *
+ * Returned Value:
+ * None.
+ *
+ ****************************************************************************/
+
+static void psram_read_data(uint8_t *buf, uint32_t addr, uint32_t len)
+{
+#if CONFIG_ESP32S3_SPIRAM_MODE_OCT
+
+ /* Clear MSPI hw fifo */
+
+ for (int i = 0; i < 16; i++)
+ {
+ REG_WRITE(SPI_MEM_W0_REG(1) + i * 4, 0);
}
+
+ esp_rom_opiflash_exec_cmd(1, ESP_ROM_SPIFLASH_OPI_DTR_MODE,
+ OPI_PSRAM_SYNC_READ, 16,
+ addr, 32,
+ OCT_PSRAM_RD_DUMMY_NUM,
+ NULL, 0,
+ buf, len * 8,
+ BIT(1),
+ false);
+#elif CONFIG_ESP32S3_SPIRAM_MODE_QUAD
+ psram_exec_cmd(1, 0,
+ QPI_PSRAM_FAST_READ, 8,
+ addr, 24,
+ QPI_PSRAM_FAST_READ_DUMMY + g_psram_extra_dummy,
+ NULL, 0,
+ buf, len * 8,
+ SPI_MEM_CS1_DIS_M,
+ false);
+#endif
+}
+
+/****************************************************************************
+ * Name: psram_write_data
+ *
+ * Description:
+ * Configure PSRAM to write data via SPI1.
+ *
+ * Input Parameters:
+ * buf - data buffer pointer
+ * addr - target address value
+ * len - data length
+ *
+ * Returned Value:
+ * None.
+ *
+ ****************************************************************************/
+
+static void psram_write_data(uint8_t *buf, uint32_t addr, uint32_t len)
+{
+#if CONFIG_ESP32S3_SPIRAM_MODE_OCT
+ esp_rom_opiflash_exec_cmd(1, ESP_ROM_SPIFLASH_OPI_DTR_MODE,
+ OPI_PSRAM_SYNC_WRITE, 16,
+ addr, 32,
+ OCT_PSRAM_WR_DUMMY_NUM,
+ buf, len * 8,
+ NULL, 0,
+ BIT(1),
+ false);
+#elif CONFIG_ESP32S3_SPIRAM_MODE_QUAD
+ psram_exec_cmd(1, 0,
+ QPI_PSRAM_WRITE, 8, /* command and command bit len */
+ addr, 24, /* address and address bit len */
+ 0, /* dummy bit len */
+ buf, len * 8, /* tx data and tx bit len */
+ NULL, 0, /* rx data and rx bit len */
+ SPI_MEM_CS1_DIS_M, /* cs bit mask */
+ false); /* whether is program/erase operation */
+#endif
+}
+
+/****************************************************************************
+ * Name: config_psram_read_write_data
+ *
+ * Description:
+ * Configure PSRAM to read or write data via SPI1.
+ *
+ * Input Parameters:
+ * buf - data buffer pointer
+ * addr - target address value
+ * len - data length
+ * is_read - is read or write
+ *
+ * Returned Value:
+ * None.
+ *
+ ****************************************************************************/
+
+static void config_psram_read_write_data(uint8_t *buf, uint32_t addr,
+ uint32_t len, bool is_read)
+{
+ while (len)
+ {
+ uint32_t length = MIN(len, 32);
+ if (is_read)
+ {
+ psram_read_data(buf, addr, length);
+ }
+ else
+ {
+ psram_write_data(buf, addr, length);
+ }
+
+ addr += length;
+ buf += length;
+ len -= length;
+ }
+}
+
+/****************************************************************************
+ * Name: get_psram_tuning_configs
+ *
+ * Description:
+ * Get PSRAM tuning configuration.
+ *
+ * Input Parameters:
+ * config - tuning timing configuration pointer
+ *
+ * Returned Value:
+ * None.
+ *
+ ****************************************************************************/
+
+static void get_psram_tuning_configs(tuning_config_s *config)
+{
+#if MSPI_TIMING_PSRAM_DTR_MODE
+# define PSRAM_MODE DTR_MODE
+#else
+# define PSRAM_MODE STR_MODE
+#endif
+
+#if CONFIG_ESP32S3_SPIRAM_SPEED_40M
+ *config = MSPI_TIMING_PSRAM_GET_TUNING_CONFIG(
+ ESP32S3_SPI_TIMING_CORE_CLK, 40, PSRAM_MODE);
+#elif CONFIG_ESP32S3_SPIRAM_SPEED_80M
+ *config = MSPI_TIMING_PSRAM_GET_TUNING_CONFIG(
+ ESP32S3_SPI_TIMING_CORE_CLK, 80, PSRAM_MODE);
+#elif CONFIG_ESP32S3_SPIRAM_SPEED_120M
+ *config = MSPI_TIMING_PSRAM_GET_TUNING_CONFIG(
+ ESP32S3_SPI_TIMING_CORE_CLK, 120, PSRAM_MODE);
+#endif
+
+#undef PSRAM_MODE
+}
+
+/****************************************************************************
+ * Name: config_psram_set_tuning_regs
+ *
+ * Description:
+ * Tune PSRAM timing registers for SPI1 accessing PSRAM
+ *
+ * Input Parameters:
+ * params - tuning timing parameters pointer
+ *
+ * Returned Value:
+ * None.
+ *
+ ****************************************************************************/
+
+static void config_psram_set_tuning_regs(const tuning_param_s *params)
+{
+ /* 1. SPI_MEM_SPI_SMEM_DINx_MODE(1), SPI_MEM_SPI_SMEM_DINx_NUM(1) are
+ * meaningless SPI0 and SPI1 share the SPI_MEM_SPI_SMEM_DINx_MODE(0),
+ * SPI_MEM_SPI_SMEM_DINx_NUM(0) for PSRAM timing tuning
+ * 2. We use SPI1 to get the best PSRAM timing tuning (mode and num) config
+ */
+
+ set_psram_din_mode_num(0, params->spi_din_mode, params->spi_din_num);
+#if CONFIG_ESP32S3_SPIRAM_MODE_OCT
+
+ /* On 728, for SPI1, flash and psram share the extra dummy register */
+
+ set_flash_extra_dummy(1, params->extra_dummy_len);
+#elif CONFIG_ESP32S3_SPIRAM_MODE_QUAD
+
+ /* Update this `g_psram_extra_dummy`, the `psram_read_data` will
+ * set dummy according to this `g_psram_extra_dummy`
+ */
+
+ g_psram_extra_dummy = params->extra_dummy_len;
+
+ /* Set MSPI Quad Flash dummy */
+
+ SET_PERI_REG_MASK(SPI_MEM_USER_REG(1), SPI_MEM_USR_DUMMY);
+ SET_PERI_REG_BITS(SPI_MEM_USER1_REG(1), SPI_MEM_USR_DUMMY_CYCLELEN_V,
+ g_psram_extra_dummy - 1, SPI_MEM_USR_DUMMY_CYCLELEN_S);
+#endif
+}
+#endif
+
+/****************************************************************************
+ * Name: sweep_for_success_sample_points
+ *
+ * Description:
+ * Use different SPI1 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.
+ *
+ * Input Parameters:
+ * reference_data - reference data pointer
+ * config - tuning timing configuration pointer
+ * is_flash - is flash or not
+ * out_array - last success point pointer
+ *
+ * Returned Value:
+ * None.
+ *
+ ****************************************************************************/
+
+static void sweep_for_success_sample_points(const uint8_t *reference_data,
+ const tuning_config_s *config, bool is_flash, uint8_t *out_array)
+{
+ uint32_t config_idx = 0;
+ uint8_t read_data[MSPI_TIMING_TEST_DATA_LEN] =
+ {
+ 0
+ };
+
+ for (config_idx = 0; config_idx < config->config_num; config_idx++)
+ {
+ memset(read_data, 0, MSPI_TIMING_TEST_DATA_LEN);
+#if ESP32S3_SPI_TIMING_FLASH_TUNING
+ if (is_flash)
+ {
+ config_flash_set_tuning_regs(&(config->config_table[config_idx]));
+ config_flash_read_data(read_data, MSPI_TIMING_FLASH_TEST_DATA_ADDR,
+ sizeof(read_data));
+ }
+#endif
+
+#if ESP32S3_SPI_TIMING_PSRAM_TUNING
+ if (!is_flash)
+ {
+ config_psram_set_tuning_regs(&(config->config_table[config_idx]));
+ config_psram_read_write_data(read_data,
+ MSPI_TIMING_PSRAM_TEST_DATA_ADDR,
+ MSPI_TIMING_TEST_DATA_LEN, true);
+ }
+
+#endif
+ if (memcmp(reference_data, read_data, sizeof(read_data)) == 0)
+ {
+ out_array[config_idx] = 1;
+ minfo("%d, good\n", config_idx);
+ }
+ else
+ {
+ minfo("%d, bad\n", config_idx);
+ }
+ }
+}
+
+/****************************************************************************
+ * Name: find_max_consecutive_success_points
+ *
+ * Description:
+ * Find max consecutive success points.
+ *
+ * Input Parameters:
+ * array - sampling results pointer
+ * size - sampling results length
+ * out_length - consecutive length pointer
+ * out_end_index - last success point pointer
+ *
+ * Returned Value:
+ * None.
+ *
+ ****************************************************************************/
+
+static void find_max_consecutive_success_points(uint8_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])
+ {
+ 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;
+}
+
+/****************************************************************************
+ * Name: select_best_tuning_config_str
+ *
+ * Description:
+ * Select the STR best point
+ *
+ * Input Parameters:
+ * config - tuning timing configuration pointer
+ * consecutive_length - consecutive length
+ * end - last success point
+ *
+ * Returned Value:
+ * Returns the STR best point.
+ *
+ ****************************************************************************/
+
+#if MSPI_TIMING_FLASH_STR_MODE || MSPI_TIMING_PSRAM_STR_MODE
+static uint32_t select_best_tuning_config_str(tuning_config_s *config,
+ uint32_t consecutive_length, uint32_t end)
+{
+#if (ESP32S3_SPI_TIMING_CORE_CLK == 120 || ESP32S3_SPI_TIMING_CORE_CLK == 240)
+ minfo("DO NOT USE FOR MASS PRODUCTION! Timing parameters may be updated");
+
+ /* STR best point scheme */
+
+ uint32_t best_point;
+ if (consecutive_length <= 2 || consecutive_length >= 5)
+ {
+ /* tuning is FAIL, select default point, and generate a warning */
+
+ best_point = config->default_config_id;
+ minfo("tuning fail, best point is fallen back to index %d\n",
+ best_point);
+ }
+ else
+ {
+ /* consecutive length : 3 or 4 */
+
+ best_point = end - consecutive_length / 2;
+ minfo("tuning success, best point is index %d\n", best_point);
+ }
+
+ return best_point;
+#else
+ /* won't reach here */
+
+ abort();
+#endif
+}
+#endif
+
+/****************************************************************************
+ * Name: select_best_tuning_config_dtr
+ *
+ * Description:
+ * Select the DTR best point
+ *
+ * Input Parameters:
+ * config - tuning timing configuration pointer
+ * consecutive_length - consecutive length
+ * end - last success point
+ *
+ * Returned Value:
+ * Returns the DTR best point.
+ *
+ ****************************************************************************/
+
+#if MSPI_TIMING_FLASH_DTR_MODE || MSPI_TIMING_PSRAM_DTR_MODE
+static uint32_t select_best_tuning_config_dtr(tuning_config_s *config,
+ uint32_t consecutive_length, uint32_t end)
+{
+#if (ESP32S3_SPI_TIMING_CORE_CLK == 160)
+
+ /* Core clock 160M DTR best point scheme */
+
+ uint32_t best_point;
+
+ /* These numbers will probably be same on other chips,
+ * if this version of algorithm is utilised
+ */
+
+ if (consecutive_length <= 2 || consecutive_length >= 6)
+ {
+ /* tuning is FAIL, select default point, and generate a warning */
+
+ best_point = config->default_config_id;
+ minfo("tuning fail, best point is fallen back to index %d\n",
+ best_point);
+ }
+ else if (consecutive_length <= 4)
+ {
+ /* consecutive length : 3 or 4 */
+
+ best_point = end - 1;
+ minfo("tuning success, best point is index %d\n", best_point);
+ }
+ else
+ {
+ /* consecutive point list length equals 5 */
+
+ best_point = end - 2;
+ minfo("tuning success, best point is index %d\n", best_point);
+ }
+
+ return best_point;
+#else
+ /* won't reach here */
+
+ abort();
Review Comment:
I've confirmed `abort()` function will block system here.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]