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