1 /*
2 * SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <sys/param.h>
8 #include "sdkconfig.h"
9 #include "string.h"
10 #include "esp_attr.h"
11 #include "esp_err.h"
12 #include "esp_types.h"
13 #include "esp_log.h"
14 #include "soc/spi_mem_reg.h"
15 #include "hal/mspi_timing_tuning_ll.h"
16 #include "../../mspi_timing_config.h"
17 #include "bootloader_flash.h"
18 #include "esp32s3/rom/spi_flash.h"
19 #include "esp32s3/rom/opi_flash.h"
20
21 #define OPI_PSRAM_SYNC_READ 0x0000
22 #define OPI_PSRAM_SYNC_WRITE 0x8080
23 #define OCT_PSRAM_RD_DUMMY_NUM (2*(10-1))
24 #define OCT_PSRAM_WR_DUMMY_NUM (2*(5-1))
25
26 #define QPI_PSRAM_FAST_READ 0XEB
27 #define QPI_PSRAM_WRITE 0X38
28 #define QPI_PSRAM_FAST_READ_DUMMY 6
29
30 #define NOT_INIT_INT 127
31
32 //-------------------------------------MSPI Clock Setting-------------------------------------//
mspi_timing_config_get_core_clock(void)33 mspi_timing_config_core_clock_t mspi_timing_config_get_core_clock(void)
34 {
35 switch (MSPI_TIMING_CORE_CLOCK_MHZ) {
36 case 80:
37 return MSPI_TIMING_CONFIG_CORE_CLOCK_80M;
38 case 120:
39 return MSPI_TIMING_CONFIG_CORE_CLOCK_120M;
40 case 160:
41 return MSPI_TIMING_CONFIG_CORE_CLOCK_160M;
42 case 240:
43 return MSPI_TIMING_CONFIG_CORE_CLOCK_240M;
44 default:
45 abort();
46 }
47 }
48
mspi_timing_config_set_core_clock(uint8_t spi_num,mspi_timing_config_core_clock_t core_clock)49 void mspi_timing_config_set_core_clock(uint8_t spi_num, mspi_timing_config_core_clock_t core_clock)
50 {
51 uint32_t reg_val = 0;
52
53 switch (core_clock) {
54 case MSPI_TIMING_CONFIG_CORE_CLOCK_80M:
55 reg_val = 0;
56 break;
57 case MSPI_TIMING_CONFIG_CORE_CLOCK_120M:
58 reg_val = 1;
59 break;
60 case MSPI_TIMING_CONFIG_CORE_CLOCK_160M:
61 reg_val = 2;
62 break;
63 case MSPI_TIMING_CONFIG_CORE_CLOCK_240M:
64 reg_val = 3;
65 break;
66 default:
67 abort();
68 }
69
70 mspi_timing_ll_set_core_clock_divider(spi_num, reg_val);
71 }
72
mspi_timing_config_set_flash_clock(uint8_t spi_num,uint32_t freqdiv)73 void mspi_timing_config_set_flash_clock(uint8_t spi_num, uint32_t freqdiv)
74 {
75 assert(freqdiv > 0);
76 mspi_timing_ll_set_flash_clock(spi_num, freqdiv);
77 }
78
mspi_timing_config_set_psram_clock(uint8_t spi_num,uint32_t freqdiv)79 void mspi_timing_config_set_psram_clock(uint8_t spi_num, uint32_t freqdiv)
80 {
81 mspi_timing_ll_set_psram_clock(spi_num, freqdiv);
82 }
83
84 /////////////////////////////////////////TIMING TUNING IS NEEDED//////////////////////////////////////////////
85 //////////////////////////////////////////////////////////////////////////////////////////////////////////////
86 #if MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING
87 //If one of the FLASH / PSRAM or both of them need timing tuning, we should build following code
88 typedef enum {
89 PSRAM_CMD_QPI,
90 PSRAM_CMD_SPI,
91 } psram_cmd_mode_t;
92
93 static uint8_t s_rom_flash_extra_dummy[2] = {NOT_INIT_INT, NOT_INIT_INT};
94
95 #if CONFIG_SPIRAM_MODE_QUAD
96 static uint8_t s_psram_extra_dummy;
97 extern void psram_exec_cmd(int spi_num, psram_cmd_mode_t mode,
98 uint32_t cmd, int cmd_bit_len,
99 uint32_t addr, int addr_bit_len,
100 int dummy_bits,
101 uint8_t* mosi_data, int mosi_bit_len,
102 uint8_t* miso_data, int miso_bit_len,
103 uint32_t cs_mask,
104 bool is_write_erase_operation);
105 #endif
106
107 //-------------------------------------FLASH timing tuning register config-------------------------------------//
mspi_timing_config_flash_set_din_mode_num(uint8_t spi_num,uint8_t din_mode,uint8_t din_num)108 void mspi_timing_config_flash_set_din_mode_num(uint8_t spi_num, uint8_t din_mode, uint8_t din_num)
109 {
110 mspi_timing_ll_set_flash_din_mode(spi_num, din_mode);
111 mspi_timing_ll_set_flash_din_num(spi_num, din_num);
112 }
113
spi_timing_config_get_dummy(void)114 static uint32_t spi_timing_config_get_dummy(void)
115 {
116 mspi_timing_ll_flash_mode_t mode = mspi_timing_ll_get_flash_mode(0);
117 if (mode == MSPI_TIMING_LL_FLASH_OPI_MODE) {
118 abort();
119 }
120
121 #if CONFIG_SPI_FLASH_HPM_DC_ON
122 if (spi_flash_hpm_dummy_adjust()) { // HPM-DC is enabled
123 const spi_flash_hpm_dummy_conf_t *hpm_dummy = spi_flash_hpm_get_dummy();
124 switch (mode) {
125 case MSPI_TIMING_LL_FLASH_QIO_MODE:
126 return hpm_dummy->qio_dummy - 1;
127 case MSPI_TIMING_LL_FLASH_QUAD_MODE:
128 return hpm_dummy->qout_dummy - 1;
129 case MSPI_TIMING_LL_FLASH_DIO_MODE:
130 return hpm_dummy->dio_dummy - 1;
131 case MSPI_TIMING_LL_FLASH_DUAL_MODE:
132 return hpm_dummy->dout_dummy - 1;
133 case MSPI_TIMING_LL_FLASH_FAST_MODE:
134 return hpm_dummy->fastrd_dummy - 1;
135 case MSPI_TIMING_LL_FLASH_SLOW_MODE:
136 return 0;
137 default:
138 abort();
139 }
140 } else
141 #endif
142 { // HPM-DC is not enabled
143 switch (mode) {
144 case MSPI_TIMING_LL_FLASH_QIO_MODE:
145 return SPI1_R_QIO_DUMMY_CYCLELEN;
146 case MSPI_TIMING_LL_FLASH_QUAD_MODE:
147 return SPI1_R_FAST_DUMMY_CYCLELEN;
148 case MSPI_TIMING_LL_FLASH_DIO_MODE:
149 return SPI1_R_DIO_DUMMY_CYCLELEN;
150 case MSPI_TIMING_LL_FLASH_DUAL_MODE:
151 return SPI1_R_FAST_DUMMY_CYCLELEN;
152 case MSPI_TIMING_LL_FLASH_FAST_MODE:
153 return SPI1_R_FAST_DUMMY_CYCLELEN;
154 case MSPI_TIMING_LL_FLASH_SLOW_MODE:
155 return 0;
156 default:
157 abort();
158 }
159 }
160 }
161
mspi_timing_config_flash_set_extra_dummy(uint8_t spi_num,uint8_t extra_dummy)162 void mspi_timing_config_flash_set_extra_dummy(uint8_t spi_num, uint8_t extra_dummy)
163 {
164 if (bootloader_flash_is_octal_mode_enabled()) {
165 mspi_timing_ll_set_octal_flash_extra_dummy(spi_num, extra_dummy);
166 return;
167 }
168 /**
169 * HW workaround:
170 * The `SPI_MEM_TIMING_CALI_REG` register is only used for OPI on 728
171 * Here we only need to update this global variable for extra dummy. Since we use the ROM Flash API, which will set the dummy based on this.
172 * We only initialise the SPI0. And leave the SPI1 for flash driver to configure.
173 */
174 if (s_rom_flash_extra_dummy[spi_num] == NOT_INIT_INT) {
175 s_rom_flash_extra_dummy[spi_num] = g_rom_spiflash_dummy_len_plus[spi_num];
176 }
177 g_rom_spiflash_dummy_len_plus[spi_num] = s_rom_flash_extra_dummy[spi_num] + extra_dummy;
178
179 // Only Quad Flash will run into this branch.
180 uint32_t dummy = spi_timing_config_get_dummy();
181 mspi_timing_ll_set_quad_flash_dummy(spi_num, dummy + g_rom_spiflash_dummy_len_plus[spi_num]);
182 }
183
184 //-------------------------------------PSRAM timing tuning register config-------------------------------------//
mspi_timing_config_psram_set_din_mode_num(uint8_t spi_num,uint8_t din_mode,uint8_t din_num)185 void mspi_timing_config_psram_set_din_mode_num(uint8_t spi_num, uint8_t din_mode, uint8_t din_num)
186 {
187 mspi_timing_ll_set_psram_din_mode(spi_num, din_mode);
188 mspi_timing_ll_set_psram_din_num(spi_num, din_num);
189 }
190
mspi_timing_config_psram_set_extra_dummy(uint8_t spi_num,uint8_t extra_dummy)191 void mspi_timing_config_psram_set_extra_dummy(uint8_t spi_num, uint8_t extra_dummy)
192 {
193 #if CONFIG_SPIRAM_MODE_OCT
194 mspi_timing_ll_set_octal_psram_extra_dummy(spi_num, extra_dummy);
195 #elif CONFIG_SPIRAM_MODE_QUAD
196 //HW workaround: Use normal dummy register to set extra dummy, the calibration dedicated extra dummy register doesn't work for quad mode
197 mspi_timing_ll_set_quad_psram_dummy(spi_num, (QPI_PSRAM_FAST_READ_DUMMY + extra_dummy - 1));
198 #endif
199 }
200
201 //-------------------------------------------FLASH/PSRAM Read/Write------------------------------------------//
mspi_timing_config_flash_read_data(uint8_t * buf,uint32_t addr,uint32_t len)202 void mspi_timing_config_flash_read_data(uint8_t *buf, uint32_t addr, uint32_t len)
203 {
204 if (bootloader_flash_is_octal_mode_enabled()) {
205 // note that in spi_flash_read API, there is a wait-idle stage, since flash can only be read in idle state.
206 // but after we change the timing settings, we might not read correct idle status via RDSR.
207 // so, here we should use a read API that won't check idle status.
208 mspi_timing_ll_clear_fifo(1);
209 esp_rom_opiflash_read_raw(addr, buf, len);
210 } else {
211 esp_rom_spiflash_read(addr, (uint32_t *)buf, len);
212 }
213 }
214
s_psram_write_data(uint8_t * buf,uint32_t addr,uint32_t len)215 static void s_psram_write_data(uint8_t *buf, uint32_t addr, uint32_t len)
216 {
217 #if CONFIG_SPIRAM_MODE_OCT
218 esp_rom_opiflash_exec_cmd(1, ESP_ROM_SPIFLASH_OPI_DTR_MODE,
219 OPI_PSRAM_SYNC_WRITE, 16,
220 addr, 32,
221 OCT_PSRAM_WR_DUMMY_NUM,
222 buf, len * 8,
223 NULL, 0,
224 BIT(1),
225 false);
226 #elif CONFIG_SPIRAM_MODE_QUAD
227 psram_exec_cmd(1, 0,
228 QPI_PSRAM_WRITE, 8,
229 addr, 24,
230 0,
231 buf, len * 8,
232 NULL, 0,
233 SPI_MEM_CS1_DIS_M,
234 false);
235 #endif
236 }
237
s_psram_read_data(uint8_t * buf,uint32_t addr,uint32_t len)238 static void s_psram_read_data(uint8_t *buf, uint32_t addr, uint32_t len)
239 {
240 #if CONFIG_SPIRAM_MODE_OCT
241 mspi_timing_ll_clear_fifo(1);
242 esp_rom_opiflash_exec_cmd(1, ESP_ROM_SPIFLASH_OPI_DTR_MODE,
243 OPI_PSRAM_SYNC_READ, 16,
244 addr, 32,
245 OCT_PSRAM_RD_DUMMY_NUM,
246 NULL, 0,
247 buf, len * 8,
248 BIT(1),
249 false);
250 #elif CONFIG_SPIRAM_MODE_QUAD
251 psram_exec_cmd(1, 0,
252 QPI_PSRAM_FAST_READ, 8,
253 addr, 24,
254 QPI_PSRAM_FAST_READ_DUMMY + s_psram_extra_dummy,
255 NULL, 0,
256 buf, len * 8,
257 SPI_MEM_CS1_DIS_M,
258 false);
259 #endif
260 }
261
s_psram_execution(uint8_t * buf,uint32_t addr,uint32_t len,bool is_read)262 static void s_psram_execution(uint8_t *buf, uint32_t addr, uint32_t len, bool is_read)
263 {
264 while (len) {
265 uint32_t length = MIN(len, 32);
266 if (is_read) {
267 s_psram_read_data(buf, addr, length);
268 } else {
269 s_psram_write_data(buf, addr, length);
270 }
271 addr += length;
272 buf += length;
273 len -= length;
274 }
275 }
276
mspi_timing_config_psram_write_data(uint8_t * buf,uint32_t addr,uint32_t len)277 void mspi_timing_config_psram_write_data(uint8_t *buf, uint32_t addr, uint32_t len)
278 {
279 s_psram_execution(buf, addr, len, false);
280 }
281
mspi_timing_config_psram_read_data(uint8_t * buf,uint32_t addr,uint32_t len)282 void mspi_timing_config_psram_read_data(uint8_t *buf, uint32_t addr, uint32_t len)
283 {
284 s_psram_execution(buf, addr, len, true);
285 }
286
287
288 /*-------------------------------------------------------------------------------------------------
289 * SPI1 Timing Tuning APIs
290 * These APIs are only used in `spi_flash_timing_tuning.c/sweep_for_success_sample_points()` for
291 * configuring SPI1 timing tuning related registers to find best tuning parameter
292 *-------------------------------------------------------------------------------------------------*/
mspi_timing_config_flash_set_tuning_regs(const mspi_timing_tuning_param_t * params)293 void mspi_timing_config_flash_set_tuning_regs(const mspi_timing_tuning_param_t *params)
294 {
295 /**
296 * 1. SPI_MEM_DINx_MODE(1), SPI_MEM_DINx_NUM(1) are meaningless
297 * SPI0 and SPI1 share the SPI_MEM_DINx_MODE(0), SPI_MEM_DINx_NUM(0) for FLASH timing tuning
298 * 2. We use SPI1 to get the best Flash timing tuning (mode and num) config
299 */
300 mspi_timing_config_flash_set_din_mode_num(0, params->spi_din_mode, params->spi_din_num);
301 mspi_timing_config_flash_set_extra_dummy(1, params->extra_dummy_len);
302 }
303
mspi_timing_config_psram_set_tuning_regs(const mspi_timing_tuning_param_t * params)304 void mspi_timing_config_psram_set_tuning_regs(const mspi_timing_tuning_param_t *params)
305 {
306 /**
307 * 1. SPI_MEM_SPI_SMEM_DINx_MODE(1), SPI_MEM_SPI_SMEM_DINx_NUM(1) are meaningless
308 * SPI0 and SPI1 share the SPI_MEM_SPI_SMEM_DINx_MODE(0), SPI_MEM_SPI_SMEM_DINx_NUM(0) for PSRAM timing tuning
309 * 2. We use SPI1 to get the best PSRAM timing tuning (mode and num) config
310 */
311 mspi_timing_config_psram_set_din_mode_num(0, params->spi_din_mode, params->spi_din_num);
312
313 #if CONFIG_SPIRAM_MODE_OCT
314 //On 728, for SPI1, flash and psram share the extra dummy register
315 mspi_timing_config_flash_set_extra_dummy(1, params->extra_dummy_len);
316 #elif CONFIG_SPIRAM_MODE_QUAD
317 //Update this `s_psram_extra_dummy`, the `s_psram_read_data` will set dummy according to this `s_psram_extra_dummy`
318 s_psram_extra_dummy = params->extra_dummy_len;
319 mspi_timing_ll_set_quad_flash_dummy(1, s_psram_extra_dummy - 1);
320 #endif
321 }
322
323 #endif //#if MSPI_TIMING_FLASH_NEEDS_TUNING || MSPI_TIMING_PSRAM_NEEDS_TUNING
324
325
326 /*-------------------------------------------------------------------------------------------------
327 * To let upper lay (spi_flash_timing_tuning.c) to know the necessary timing registers
328 *-------------------------------------------------------------------------------------------------*/
329 /**
330 * Get the SPI1 Flash CS timing setting. The setup time and hold time are both realistic cycles.
331 * @note On ESP32-S3, SPI0/1 share the Flash CS timing registers. Therefore, we should not change these values.
332 * @note This function inform `spi_flash_timing_tuning.c` (driver layer) of the cycle,
333 * and other component (esp_flash driver) should get these cycle and configure the registers accordingly.
334 */
mspi_timing_config_get_cs_timing(uint8_t * setup_time,uint32_t * hold_time)335 void mspi_timing_config_get_cs_timing(uint8_t *setup_time, uint32_t *hold_time)
336 {
337 *setup_time = mspi_timing_ll_get_cs_setup_val(0);
338 *hold_time = mspi_timing_ll_get_cs_hold_val(0);
339 /**
340 * The logic here is, if setup_en / hold_en is false, then we return the realistic cycle number,
341 * which is 0. If true, then the realistic cycle number is (reg_value + 1)
342 */
343 if (mspi_timing_ll_is_cs_setup_enabled(0)) {
344 *setup_time += 1;
345 } else {
346 *setup_time = 0;
347 }
348 if (mspi_timing_ll_is_cs_hold_enabled(0)) {
349 *hold_time += 1;
350 } else {
351 *hold_time = 0;
352 }
353 }
354
355 /**
356 * Get the SPI1 Flash clock setting.
357 * @note Similarly, this function inform `spi_flash_timing_tuning.c` (driver layer) of the clock setting,
358 * and other component (esp_flash driver) should get these and configure the registers accordingly.
359 */
mspi_timing_config_get_flash_clock_reg(void)360 uint32_t mspi_timing_config_get_flash_clock_reg(void)
361 {
362 return mspi_timing_ll_get_clock_reg(1);
363 }
364