1 /*
2 * SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <stdint.h>
8 #include "sdkconfig.h"
9 #include "esp_err.h"
10 #include "esp_log.h"
11 #include "spi_flash_defs.h"
12 #include "esp_rom_sys.h"
13 #include "esp_rom_spiflash.h"
14 #include "spi_flash_override.h"
15
16 // TODO: These dependencies will be removed after remove bootloader_flash to G0.IDF-4609
17 #include "bootloader_flash_override.h"
18 #include "bootloader_flash_priv.h"
19
20 /*******************************************************************************
21 * Flash high speed performance mode.
22 * HPM: High performance mode.
23 * HPF: High performance flag.
24 *
25 * Different flash chips might have different high performance strategy.
26 * 1. Some flash chips send A3H to enable the HPM.
27 * 2. Some flash chips write HPF bit in status register.
28 * 3. Some flash chips adjust dummy cycles.
29 ******************************************************************************/
30
31 /*
32 * Note: This file should only be compiled when HPM_ON, which is only available when !CONFIG_ESPTOOLPY_OCT_FLASH.
33 * However when HPM_ON, there are still some cases this file is not actually used:
34 *
35 * - !CONFIG_SPI_FLASH_UNDER_HIGH_FREQ:
36 * It mean that the flash not running under frequency requires HPM. spi_flash_enable_high_performance_mode() still
37 * called because caller shouldn't take care of the frequency.
38 *
39 * - bootloader_flash_is_octal_mode_enabled() == true:
40 * This is possible when `CONFIG_ESPTOOLPY_FLASH_MODE_AUTO_DETECT` selected
41 *
42 * Octal Flash for now all support 120M. No need to enable HPM. The file is compiled, but will not actually run
43 * into spi_flash_enable_high_performance_mode().
44 */
45
46 void spi_flash_hpm_get_dummy_generic(spi_flash_hpm_dummy_conf_t *dummy_conf);
47
48 #if CONFIG_SPI_FLASH_UNDER_HIGH_FREQ
49
50 #if CONFIG_SPI_FLASH_HPM_AUTO
51 // This only happens on S3, where HPM_AUTO leads to HPM_ON
52 #warning High Performance Mode (QSPI Flash > 80MHz) is optional feature that depends on flash model. Read Docs First!
53 #endif
54
55 const static char *HPM_TAG = "flash HPM";
56
57 // TODO: This function will be changed after remove bootloader_flash to G0.IDF-4609
58 extern uint32_t bootloader_flash_execute_command_common(
59 uint8_t command,
60 uint32_t addr_len, uint32_t address,
61 uint8_t dummy_len,
62 uint8_t mosi_len, uint32_t mosi_data,
63 uint8_t miso_len);
64
65 extern uint32_t IRAM_ATTR bootloader_flash_read_sfdp(uint32_t sfdp_addr, unsigned int miso_byte_num);
66
67 //-----------------For flash chips which enter HPM via command-----------------------//
68
69 /**
70 * @brief Probe the chip whether use command to enable HPM mode. Take GD as an example:
71 * Some GD send 0xA3 command to enable HPM mode of the flash.
72 */
spi_flash_hpm_probe_chip_with_cmd(uint32_t flash_id)73 static esp_err_t spi_flash_hpm_probe_chip_with_cmd(uint32_t flash_id)
74 {
75 esp_err_t ret = ESP_OK;
76 uint32_t gd_sfdp;
77
78 switch (flash_id) {
79 /* The flash listed here should enter the HPM with command 0xA3 */
80 case 0xC84016:
81 case 0xC84017:
82 // Read BYTE4 in SFDP, 0 means C series, 6 means E series
83 gd_sfdp = bootloader_flash_read_sfdp(0x4, 1);
84 if (gd_sfdp == 0x0) {
85 break;
86 } else {
87 ret = ESP_ERR_NOT_FOUND;
88 break;
89 }
90 default:
91 ret = ESP_ERR_NOT_FOUND;
92 break;
93 }
94 return ret;
95 }
96
spi_flash_hpm_chip_hpm_requirement_check_with_cmd(uint32_t flash_id,uint32_t freq_mhz,int voltage_mv,int temperautre)97 static spi_flash_requirement_t spi_flash_hpm_chip_hpm_requirement_check_with_cmd(uint32_t flash_id, uint32_t freq_mhz, int voltage_mv, int temperautre)
98 {
99 // voltage and temperature are not been used now, to be completed in the future.
100 (void)voltage_mv;
101 (void)temperautre;
102 spi_flash_requirement_t chip_cap = SPI_FLASH_HPM_UNNEEDED;
103 if (freq_mhz > 80) {
104 chip_cap = SPI_FLASH_HPM_CMD_NEEDED;
105 }
106 ESP_EARLY_LOGD(HPM_TAG, "HPM with command, status is %d", chip_cap);
107 return chip_cap;
108 }
109
110 /**
111 * @brief Send HPMEN command (A3H)
112 */
spi_flash_enable_high_performance_send_cmd(void)113 static void spi_flash_enable_high_performance_send_cmd(void)
114 {
115 uint32_t dummy = 24;
116 bootloader_flash_execute_command_common(CMD_HPMEN, 0, 0, dummy, 0, 0, 0);
117 // Delay for T(HPM) referring to datasheet.
118 esp_rom_delay_us(20);
119 }
120
121 /**
122 * @brief Check whether flash HPM has been enabled. According to flash datasheets, majorities of
123 * HPF bit are at bit-5, sr-3. But some are not. Therefore, this function is only used for those
124 * HPF bit is at bit-5, sr-3.
125 */
spi_flash_high_performance_check_hpf_bit_5(void)126 static esp_err_t spi_flash_high_performance_check_hpf_bit_5(void)
127 {
128 if((bootloader_read_status_8b_rdsr3() & (1 << 4)) == 0) {
129 return ESP_FAIL;
130 }
131 return ESP_OK;
132 }
133
134 //-----------------For flash chips which enter HPM via adjust dummy-----------------------//
135
136 #if CONFIG_SPI_FLASH_HPM_DC_ON
137 /**
138 * @brief Probe the chip whether adjust dummy to enable HPM mode. Take XMC as an example:
139 * Adjust dummy bits to enable HPM mode of the flash. If XMC works under 80MHz, the dummy bits
140 * might be 6, but when works under 120MHz, the dummy bits might be 10.
141 */
spi_flash_hpm_probe_chip_with_dummy(uint32_t flash_id)142 static esp_err_t spi_flash_hpm_probe_chip_with_dummy(uint32_t flash_id)
143 {
144 esp_err_t ret = ESP_OK;
145 uint32_t gd_sfdp;
146
147 switch (flash_id) {
148 /* The flash listed here should enter the HPM by adjusting dummy cycles */
149 // XMC chips.
150 case 0x204017:
151 case 0x204018:
152 case 0x464016:
153 case 0x464017:
154 case 0x464018:
155 break;
156 // GD chips.
157 case 0xC84017:
158 case 0xC84018:
159 // Read BYTE4 in SFDP, 0 means C series, 6 means E series
160 gd_sfdp = bootloader_flash_read_sfdp(0x4, 1);
161 if (gd_sfdp == 0x6) {
162 break;
163 } else {
164 ret = ESP_ERR_NOT_FOUND;
165 break;
166 }
167 default:
168 ret = ESP_ERR_NOT_FOUND;
169 break;
170 }
171 return ret;
172 }
173
spi_flash_hpm_chip_hpm_requirement_check_with_dummy(uint32_t flash_id,uint32_t freq_mhz,int voltage_mv,int temperautre)174 static spi_flash_requirement_t spi_flash_hpm_chip_hpm_requirement_check_with_dummy(uint32_t flash_id, uint32_t freq_mhz, int voltage_mv, int temperautre)
175 {
176 // voltage and temperature are not been used now, to be completed in the future.
177 (void)voltage_mv;
178 (void)temperautre;
179 spi_flash_requirement_t chip_cap = SPI_FLASH_HPM_UNNEEDED;
180
181 if (freq_mhz >= 104) {
182 chip_cap = SPI_FLASH_HPM_DUMMY_NEEDED;
183 }
184 ESP_EARLY_LOGD(HPM_TAG, "HPM with dummy, status is %d", chip_cap);
185 return chip_cap;
186 }
187
188 /**
189 * @brief Adjust dummy cycles. This function modifies the Dummy Cycle Bits in SR3.
190 * Usually, the bits are at bit-0, bit-1, sr-3 and set DC[1:0]=[1,1].
191 *
192 * @note Don't forget to adjust dummy configurations for MSPI, you can get the
193 * correct dummy from interface `spi_flash_hpm_get_dummy`.
194 */
spi_flash_turn_high_performance_reconfig_dummy(void)195 static void spi_flash_turn_high_performance_reconfig_dummy(void)
196 {
197 uint8_t old_status_3 = bootloader_read_status_8b_rdsr3();
198 uint8_t new_status = (old_status_3 | 0x03);
199 bootloader_execute_flash_command(CMD_WRENVSR, 0, 0, 0);
200 bootloader_write_status_8b_wrsr3(new_status);
201 esp_rom_spiflash_wait_idle(&g_rom_flashchip);
202 }
203
204 /**
205 * @brief Check whether HPM has been enabled. This function checks the DC bits
206 */
spi_flash_high_performance_check_dummy_sr(void)207 static esp_err_t spi_flash_high_performance_check_dummy_sr(void)
208 {
209 if((bootloader_read_status_8b_rdsr3() & 0x03) == 0) {
210 return ESP_FAIL;
211 }
212 return ESP_OK;
213 }
214
spi_flash_hpm_get_dummy_xmc(spi_flash_hpm_dummy_conf_t * dummy_conf)215 static void spi_flash_hpm_get_dummy_xmc(spi_flash_hpm_dummy_conf_t *dummy_conf)
216 {
217 dummy_conf->dio_dummy = SPI_FLASH_DIO_HPM_DUMMY_BITLEN;
218 dummy_conf->dout_dummy = SPI_FLASH_DOUT_DUMMY_BITLEN;
219 dummy_conf->qio_dummy = SPI_FLASH_QIO_HPM_DUMMY_BITLEN;
220 dummy_conf->qout_dummy = SPI_FLASH_QOUT_DUMMY_BITLEN;
221 dummy_conf->fastrd_dummy = SPI_FLASH_FASTRD_DUMMY_BITLEN;
222 }
223 #elif !CONFIG_SPI_FLASH_HPM_DC_DISABLE
224
225 //This is because bootloader doesn't support this
226 #warning HPM-DC, which helps to run some flash > 80MHz by adjusting dummy cycles, is no longer enabled by default.
227 #warning To enable this feature, your bootloader needs to have the support for it (by explicitly selecting BOOTLOADER_FLASH_DC_AWARE).
228 #warning If your bootloader does not support it, select SPI_FLASH_HPM_DC_DISABLE to suppress the warning. READ DOCS FIRST!
229
230 #endif //CONFIG_SPI_FLASH_HPM_DC_ON
231
232 //-----------------For flash chips which enter HPM via write status register-----------------------//
233
234 /**
235 * @brief Probe the chip whether to write status register to enable HPM mode. Take ZB as an example:
236 * Write status register bits to enable HPM mode of the flash. If ZB works under 80MHz, the register value
237 * would be 0, but when works under 120MHz, the register value would be 1.
238 */
spi_flash_hpm_probe_chip_with_write_hpf_bit_5(uint32_t flash_id)239 static esp_err_t spi_flash_hpm_probe_chip_with_write_hpf_bit_5(uint32_t flash_id)
240 {
241 esp_err_t ret = ESP_OK;
242 switch (flash_id) {
243 /* The flash listed here should enter the HPM by adjusting dummy cycles */
244 // ZB chips.
245 case 0x5E4016:
246 break;
247 default:
248 ret = ESP_ERR_NOT_FOUND;
249 break;
250 }
251 return ret;
252 }
253
spi_flash_hpm_chip_hpm_requirement_check_with_write_hpf_bit_5(uint32_t flash_id,uint32_t freq_mhz,int voltage_mv,int temperautre)254 static spi_flash_requirement_t spi_flash_hpm_chip_hpm_requirement_check_with_write_hpf_bit_5(uint32_t flash_id, uint32_t freq_mhz, int voltage_mv, int temperautre)
255 {
256 // voltage and temperature are not been used now, to be completed in the future.
257 (void)voltage_mv;
258 (void)temperautre;
259 spi_flash_requirement_t chip_cap = SPI_FLASH_HPM_UNNEEDED;
260
261 if (freq_mhz >= 104) {
262 chip_cap = SPI_FLASH_HPM_WRITE_SR_NEEDED;
263 }
264 ESP_EARLY_LOGD(HPM_TAG, "HPM with dummy, status is %d", chip_cap);
265 return chip_cap;
266 }
267
268 /**
269 * @brief Write bit 5 in status 3
270 */
spi_flash_turn_high_performance_write_hpf_bit_5(void)271 static void spi_flash_turn_high_performance_write_hpf_bit_5(void)
272 {
273 uint8_t old_status_3 = bootloader_read_status_8b_rdsr3();
274 uint8_t new_status = (old_status_3 | 0x10);
275 bootloader_execute_flash_command(CMD_WRENVSR, 0, 0, 0);
276 bootloader_write_status_8b_wrsr3(new_status);
277 esp_rom_spiflash_wait_idle(&g_rom_flashchip);
278 }
279
280 const spi_flash_hpm_info_t __attribute__((weak)) spi_flash_hpm_enable_list[] = {
281 /* vendor, chip_id, freq_threshold, temperature threshold, operation for setting high performance, reading HPF status, get dummy */
282 { "command", spi_flash_hpm_probe_chip_with_cmd, spi_flash_hpm_chip_hpm_requirement_check_with_cmd, spi_flash_enable_high_performance_send_cmd, spi_flash_high_performance_check_hpf_bit_5, spi_flash_hpm_get_dummy_generic },
283 #if CONFIG_SPI_FLASH_HPM_DC_ON
284 { "dummy", spi_flash_hpm_probe_chip_with_dummy, spi_flash_hpm_chip_hpm_requirement_check_with_dummy, spi_flash_turn_high_performance_reconfig_dummy, spi_flash_high_performance_check_dummy_sr, spi_flash_hpm_get_dummy_xmc},
285 #endif //CONFIG_SPI_FLASH_HPM_DC_ON
286 { "write sr3-bit5", spi_flash_hpm_probe_chip_with_write_hpf_bit_5, spi_flash_hpm_chip_hpm_requirement_check_with_write_hpf_bit_5, spi_flash_turn_high_performance_write_hpf_bit_5, spi_flash_high_performance_check_hpf_bit_5, spi_flash_hpm_get_dummy_generic},
287 // default: do nothing, but keep the dummy get function. The first item with NULL as its probe will be the fallback.
288 { "NULL", NULL, NULL, NULL, NULL, spi_flash_hpm_get_dummy_generic},
289 };
290
291 static const spi_flash_hpm_info_t *chip_hpm = NULL;
292
293 #if CONFIG_SPI_FLASH_HPM_DC_ON
294 static bool s_hpm_dummy_changed = false;
295 static spi_flash_hpm_dummy_conf_t s_dummy_conf;
296
spi_flash_hpm_get_dummy(void)297 const spi_flash_hpm_dummy_conf_t *spi_flash_hpm_get_dummy(void)
298 {
299 chip_hpm->flash_get_dummy(&s_dummy_conf);
300 return &s_dummy_conf;
301 }
302
spi_flash_hpm_dummy_adjust(void)303 bool spi_flash_hpm_dummy_adjust(void)
304 {
305 return s_hpm_dummy_changed;
306 }
307 #endif //CONFIG_SPI_FLASH_HPM_DC_ON
308
309 #if CONFIG_ESPTOOLPY_FLASHFREQ_120M
310 #define FLASH_FREQUENCY 120
311 #endif
312
spi_flash_enable_high_performance_mode(void)313 esp_err_t spi_flash_enable_high_performance_mode(void)
314 {
315 uint32_t flash_chip_id = g_rom_flashchip.device_id;
316 uint32_t flash_freq = FLASH_FREQUENCY;
317 spi_flash_requirement_t hpm_requirement_check;
318 // voltage and temperature has not been implemented, just leave an interface here. Complete in the future.
319 int voltage = 0;
320 int temperature = 0;
321
322 #if CONFIG_SPI_FLASH_HPM_AUTO
323 ESP_EARLY_LOGW(HPM_TAG, "HPM mode is optional feature that depends on flash model. Read Docs First!");
324 #endif
325
326 #if CONFIG_SPI_FLASH_HPM_DC_DISABLE
327 // case 1: force disabled
328 ESP_EARLY_LOGI(HPM_TAG, "w/o HPM-DC support");
329 #elif CONFIG_SPI_FLASH_HPM_DC_ON
330 // case 2: auto, and actually enabled
331 ESP_EARLY_LOGI(HPM_TAG, "with HPM-DC support");
332 #else
333 // case 3: auto, but disabled (not supported by bootloader)
334 ESP_EARLY_LOGW(HPM_TAG, "HPM mode with DC adjustment is disabled. Some flash models may not be supported. Read Docs First!");
335 #endif
336
337 const spi_flash_hpm_info_t *chip = spi_flash_hpm_enable_list;
338 esp_err_t ret = ESP_OK;
339 while (chip->probe) {
340 ret = chip->probe(flash_chip_id);
341 if (ret == ESP_OK) {
342 break;
343 }
344 chip++;
345 }
346 chip_hpm = chip;
347
348 /* When > 80 MHz, flash chips usually need special HPM support to run normally. The support is chip-specific. When
349 * the chip is not in the known flash list, nothing will be done and there will be an warning.
350 * When <= 80 MHz, it's assumed that all flash chips can run without chip-specific HPM support. This function will not be called and there will be no warning.
351 */
352 if (ret != ESP_OK) {
353 ESP_EARLY_LOGW(HPM_TAG, "High performance mode of this flash model hasn't been supported.");
354 return ret;
355 }
356
357 hpm_requirement_check = chip_hpm->chip_hpm_requirement_check(flash_chip_id, flash_freq, voltage, temperature);
358 if ((hpm_requirement_check == SPI_FLASH_HPM_CMD_NEEDED) || (hpm_requirement_check == SPI_FLASH_HPM_DUMMY_NEEDED) || (hpm_requirement_check == SPI_FLASH_HPM_WRITE_SR_NEEDED)) {
359 ESP_EARLY_LOGI(HPM_TAG, "Enabling flash high speed mode by %s", chip_hpm->method);
360 chip_hpm->flash_hpm_enable();
361 ESP_EARLY_LOGD(HPM_TAG, "Checking whether HPM has been executed");
362
363 if (chip_hpm->flash_hpf_check() != ESP_OK) {
364 ESP_EARLY_LOGE(HPM_TAG, "Flash high performance mode hasn't been executed successfully");
365 return ESP_FAIL;
366 }
367 #if CONFIG_SPI_FLASH_HPM_DC_ON
368 s_hpm_dummy_changed = (hpm_requirement_check == SPI_FLASH_HPM_DUMMY_NEEDED) ? true : false;
369 #else
370 assert(hpm_requirement_check != SPI_FLASH_HPM_DUMMY_NEEDED);
371 #endif
372 } else if (hpm_requirement_check == SPI_FLASH_HPM_BEYOND_LIMIT) {
373 ESP_EARLY_LOGE(HPM_TAG, "Flash does not have the ability to raise to that frequency");
374 return ESP_FAIL;
375 }
376 return ESP_OK;
377 }
378 #else
379 //!CONFIG_SPI_FLASH_UNDER_HIGH_FREQ
380
381 static spi_flash_hpm_dummy_conf_t s_dummy_conf;
382
spi_flash_enable_high_performance_mode(void)383 esp_err_t spi_flash_enable_high_performance_mode(void)
384 {
385 return ESP_OK;
386 }
387
spi_flash_hpm_get_dummy(void)388 const spi_flash_hpm_dummy_conf_t *spi_flash_hpm_get_dummy(void)
389 {
390 spi_flash_hpm_get_dummy_generic(&s_dummy_conf);
391 return &s_dummy_conf;
392 }
393
spi_flash_hpm_dummy_adjust(void)394 bool spi_flash_hpm_dummy_adjust(void)
395 {
396 return false;
397 }
398 #endif //CONFIG_SPI_FLASH_UNDER_HIGH_FREQ
399
400 //-----------------------generic functions-------------------------------------//
401
402 /**
403 * @brief Default dummy for almost all flash chips. If your flash doesn't need to reconfigure dummy,
404 * just call this function.
405 */
spi_flash_hpm_get_dummy_generic(spi_flash_hpm_dummy_conf_t * dummy_conf)406 void __attribute__((weak)) spi_flash_hpm_get_dummy_generic(spi_flash_hpm_dummy_conf_t *dummy_conf)
407 {
408 dummy_conf->dio_dummy = SPI_FLASH_DIO_DUMMY_BITLEN;
409 dummy_conf->dout_dummy = SPI_FLASH_DOUT_DUMMY_BITLEN;
410 dummy_conf->qio_dummy = SPI_FLASH_QIO_DUMMY_BITLEN;
411 dummy_conf->qout_dummy = SPI_FLASH_QOUT_DUMMY_BITLEN;
412 dummy_conf->fastrd_dummy = SPI_FLASH_FASTRD_DUMMY_BITLEN;
413 }
414