1 /*
2  * SPDX-FileCopyrightText: 2020-2022 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 #if CONFIG_ESPTOOLPY_FLASHFREQ_120M
32 #define FLASH_FREQUENCY 120
33 #elif CONFIG_ESPTOOLPY_FLASHFREQ_80M
34 #define FLASH_FREQUENCY 80
35 #elif CONFIG_ESPTOOLPY_FLASHFREQ_40M
36 #define FLASH_FREQUENCY 40
37 #elif CONFIG_ESPTOOLPY_FLASHFREQ_20M
38 #define FLASH_FREQUENCY 20
39 #endif
40 
41 const static char *HPM_TAG = "flash HPM";
42 
43 // TODO: This function will be changed after remove bootloader_flash to G0.IDF-4609
44 extern uint32_t bootloader_flash_execute_command_common(
45     uint8_t command,
46     uint32_t addr_len, uint32_t address,
47     uint8_t dummy_len,
48     uint8_t mosi_len, uint32_t mosi_data,
49     uint8_t miso_len);
50 
51 extern uint32_t IRAM_ATTR bootloader_flash_read_sfdp(uint32_t sfdp_addr, unsigned int miso_byte_num);
52 
53 //-----------------For flash chips which enter HPM via command-----------------------//
54 
55 /**
56  * @brief Probe the chip whether use command to enable HPM mode. Take GD as an example:
57  *        Some GD send 0xA3 command to enable HPM mode of the flash.
58  */
spi_flash_hpm_probe_chip_with_cmd(uint32_t flash_id)59 static esp_err_t spi_flash_hpm_probe_chip_with_cmd(uint32_t flash_id)
60 {
61     esp_err_t ret = ESP_OK;
62     uint32_t gd_sfdp;
63 
64     switch (flash_id) {
65     /* The flash listed here should enter the HPM with command 0xA3 */
66     case 0xC84016:
67     case 0xC84017:
68         // Read BYTE4 in SFDP, 0 means C series, 6 means E series
69         gd_sfdp = bootloader_flash_read_sfdp(0x4, 1);
70         if (gd_sfdp == 0x0) {
71             break;
72         } else {
73             ret = ESP_ERR_NOT_FOUND;
74             break;
75         }
76     default:
77         ret = ESP_ERR_NOT_FOUND;
78         break;
79     }
80     return ret;
81 }
82 
spi_flash_hpm_chip_hpm_requirement_check_with_cmd(uint32_t flash_id,uint32_t freq_mhz,int voltage_mv,int temperautre)83 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)
84 {
85     // voltage and temperature are not been used now, to be completed in the future.
86     (void)voltage_mv;
87     (void)temperautre;
88     spi_flash_requirement_t chip_cap = SPI_FLASH_HPM_UNNEEDED;
89     if (freq_mhz > 80) {
90         chip_cap = SPI_FLASH_HPM_CMD_NEEDED;
91     }
92     ESP_EARLY_LOGD(HPM_TAG, "HPM with command, status is %d", chip_cap);
93     return chip_cap;
94 }
95 
96 /**
97  * @brief Send HPMEN command (A3H)
98  */
spi_flash_enable_high_performance_send_cmd(void)99 static void spi_flash_enable_high_performance_send_cmd(void)
100 {
101     uint32_t dummy = 24;
102     bootloader_flash_execute_command_common(CMD_HPMEN, 0, 0, dummy, 0, 0, 0);
103     // Delay for T(HPM) refering to datasheet.
104     esp_rom_delay_us(20);
105 }
106 
107 /**
108  * @brief Check whether flash HPM has been enabled. According to flash datasheets, majorities of
109  *        HPF bit are at bit-5, sr-3. But some are not. Therefore, this function is only used for those
110  *        HPF bit is at bit-5, sr-3.
111  */
spi_flash_high_performance_check_hpf_bit_5(void)112 static esp_err_t spi_flash_high_performance_check_hpf_bit_5(void)
113 {
114     if((bootloader_read_status_8b_rdsr3() & (1 << 4)) == 0) {
115         return ESP_FAIL;
116     }
117     return ESP_OK;
118 }
119 
120 //-----------------For flash chips which enter HPM via adjust dummy-----------------------//
121 
122 /**
123  * @brief Probe the chip whether adjust dummy to enable HPM mode. Take XMC as an example:
124  *        Adjust dummy bits to enable HPM mode of the flash. If XMC works under 80MHz, the dummy bits
125  *        might be 6, but when works under 120MHz, the dummy bits might be 10.
126  */
spi_flash_hpm_probe_chip_with_dummy(uint32_t flash_id)127 static esp_err_t spi_flash_hpm_probe_chip_with_dummy(uint32_t flash_id)
128 {
129     esp_err_t ret = ESP_OK;
130     uint32_t gd_sfdp;
131 
132     switch (flash_id) {
133     /* The flash listed here should enter the HPM by adjusting dummy cycles */
134     // XMC chips.
135     case 0x204017:
136     case 0x204018:
137         break;
138     // GD chips.
139     case 0xC84017:
140     case 0xC84018:
141         // Read BYTE4 in SFDP, 0 means C series, 6 means E series
142         gd_sfdp = bootloader_flash_read_sfdp(0x4, 1);
143         if (gd_sfdp == 0x6) {
144             break;
145         } else {
146             ret = ESP_ERR_NOT_FOUND;
147             break;
148         }
149     default:
150         ret = ESP_ERR_NOT_FOUND;
151         break;
152     }
153     return ret;
154 }
155 
spi_flash_hpm_chip_hpm_requirement_check_with_dummy(uint32_t flash_id,uint32_t freq_mhz,int voltage_mv,int temperautre)156 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)
157 {
158     // voltage and temperature are not been used now, to be completed in the future.
159     (void)voltage_mv;
160     (void)temperautre;
161     spi_flash_requirement_t chip_cap = SPI_FLASH_HPM_UNNEEDED;
162 
163     if (freq_mhz >= 104) {
164         chip_cap = SPI_FLASH_HPM_DUMMY_NEEDED;
165     }
166     ESP_EARLY_LOGD(HPM_TAG, "HPM with dummy, status is %d", chip_cap);
167     return chip_cap;
168 }
169 
170 /**
171  * @brief Adjust dummy cycles. This function modifies the Dummy Cycle Bits in SR3.
172  *        Usually, the bits are at bit-0, bit-1, sr-3 and set DC[1:0]=[1,1].
173  *
174  * @note Don't forget to adjust dummy configurations for MSPI, you can get the
175  *       correct dummy from interface `spi_flash_hpm_get_dummy`.
176  */
spi_flash_turn_high_performance_reconfig_dummy(void)177 static void spi_flash_turn_high_performance_reconfig_dummy(void)
178 {
179     uint8_t old_status_3 = bootloader_read_status_8b_rdsr3();
180     uint8_t new_status = (old_status_3 | 0x03);
181     bootloader_execute_flash_command(CMD_WRENVSR, 0, 0, 0);
182     bootloader_write_status_8b_wrsr3(new_status);
183     esp_rom_spiflash_wait_idle(&g_rom_flashchip);
184 }
185 
186 /**
187  * @brief Check whether HPM has been enabled. This function checks the DC bits
188  */
spi_flash_high_performance_check_dummy_sr(void)189 static esp_err_t spi_flash_high_performance_check_dummy_sr(void)
190 {
191     if((bootloader_read_status_8b_rdsr3() & 0x03) == 0) {
192         return ESP_FAIL;
193     }
194     return ESP_OK;
195 }
196 
spi_flash_hpm_get_dummy_xmc(spi_flash_hpm_dummy_conf_t * dummy_conf)197 static void spi_flash_hpm_get_dummy_xmc(spi_flash_hpm_dummy_conf_t *dummy_conf)
198 {
199     dummy_conf->dio_dummy = SPI_FLASH_DIO_HPM_DUMMY_BITLEN;
200     dummy_conf->dout_dummy = SPI_FLASH_DOUT_DUMMY_BITLEN;
201     dummy_conf->qio_dummy = SPI_FLASH_QIO_HPM_DUMMY_BITLEN;
202     dummy_conf->qout_dummy = SPI_FLASH_QOUT_DUMMY_BITLEN;
203     dummy_conf->fastrd_dummy = SPI_FLASH_FASTRD_DUMMY_BITLEN;
204 }
205 
206 //-----------------For flash chips which enter HPM via write status register-----------------------//
207 
208 /**
209  * @brief Probe the chip whether to write status register to enable HPM mode. Take ZB as an example:
210  *        Write status register bits to enable HPM mode of the flash. If ZB works under 80MHz, the register value
211  *        would be 0, but when works under 120MHz, the register value would be 1.
212  */
spi_flash_hpm_probe_chip_with_write_hpf_bit_5(uint32_t flash_id)213 static esp_err_t spi_flash_hpm_probe_chip_with_write_hpf_bit_5(uint32_t flash_id)
214 {
215     esp_err_t ret = ESP_OK;
216     switch (flash_id) {
217     /* The flash listed here should enter the HPM by adjusting dummy cycles */
218     // ZB chips.
219     case 0x5E4016:
220         break;
221     default:
222         ret = ESP_ERR_NOT_FOUND;
223         break;
224     }
225     return ret;
226 }
227 
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)228 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)
229 {
230     // voltage and temperature are not been used now, to be completed in the future.
231     (void)voltage_mv;
232     (void)temperautre;
233     spi_flash_requirement_t chip_cap = SPI_FLASH_HPM_UNNEEDED;
234 
235     if (freq_mhz >= 104) {
236         chip_cap = SPI_FLASH_HPM_WRITE_SR_NEEDED;
237     }
238     ESP_EARLY_LOGD(HPM_TAG, "HPM with dummy, status is %d", chip_cap);
239     return chip_cap;
240 }
241 
242 /**
243  * @brief Write bit 5 in status 3
244  */
spi_flash_turn_high_performance_write_hpf_bit_5(void)245 static void spi_flash_turn_high_performance_write_hpf_bit_5(void)
246 {
247     uint8_t old_status_3 = bootloader_read_status_8b_rdsr3();
248     uint8_t new_status = (old_status_3 | 0x10);
249     bootloader_execute_flash_command(CMD_WRENVSR, 0, 0, 0);
250     bootloader_write_status_8b_wrsr3(new_status);
251     esp_rom_spiflash_wait_idle(&g_rom_flashchip);
252 }
253 
254 //-----------------------generic functions-------------------------------------//
255 
256 /**
257  * @brief Default dummy for almost all flash chips. If your flash does't need to reconfigure dummy,
258  *        just call this function.
259  */
spi_flash_hpm_get_dummy_generic(spi_flash_hpm_dummy_conf_t * dummy_conf)260 void __attribute__((weak)) spi_flash_hpm_get_dummy_generic(spi_flash_hpm_dummy_conf_t *dummy_conf)
261 {
262     dummy_conf->dio_dummy = SPI_FLASH_DIO_DUMMY_BITLEN;
263     dummy_conf->dout_dummy = SPI_FLASH_DOUT_DUMMY_BITLEN;
264     dummy_conf->qio_dummy = SPI_FLASH_QIO_DUMMY_BITLEN;
265     dummy_conf->qout_dummy = SPI_FLASH_QOUT_DUMMY_BITLEN;
266     dummy_conf->fastrd_dummy = SPI_FLASH_FASTRD_DUMMY_BITLEN;
267 }
268 
269 const spi_flash_hpm_info_t __attribute__((weak)) spi_flash_hpm_enable_list[] = {
270     /* vendor, chip_id, freq_threshold,  temperature threshold,   operation for setting high performance,         reading HPF status,                         get dummy        */
271     { "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 },
272     { "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},
273     { "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},
274     // default: do nothing, but keep the dummy get function. The first item with NULL as its probe will be the fallback.
275     { "NULL",  NULL,                        NULL,              NULL,                            NULL,                             spi_flash_hpm_get_dummy_generic},
276 };
277 
278 static const spi_flash_hpm_info_t *chip_hpm = NULL;
279 static spi_flash_hpm_dummy_conf_t dummy_conf;
280 static bool hpm_dummy_changed = false;
281 
spi_flash_enable_high_performance_mode(void)282 esp_err_t spi_flash_enable_high_performance_mode(void)
283 {
284     uint32_t flash_chip_id = g_rom_flashchip.device_id;
285     uint32_t flash_freq = FLASH_FREQUENCY;
286     spi_flash_requirement_t hpm_requirement_check;
287     // voltage and temperature has not been implemented, just leave an interface here. Complete in the future.
288     int voltage = 0;
289     int temperature = 0;
290 
291     const spi_flash_hpm_info_t *chip = spi_flash_hpm_enable_list;
292     esp_err_t ret = ESP_OK;
293     while (chip->probe) {
294         ret = chip->probe(flash_chip_id);
295         if (ret == ESP_OK) {
296             break;
297         }
298         chip++;
299     }
300     chip_hpm = chip;
301 
302     if (ret != ESP_OK) {
303 #if (FLASH_FREQUENCY == 120)
304             ESP_EARLY_LOGW(HPM_TAG, "Flash high performance mode hasn't been supported");
305 #endif
306         return ret;
307     }
308 
309     hpm_requirement_check = chip_hpm->chip_hpm_requirement_check(flash_chip_id, flash_freq, voltage, temperature);
310     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)) {
311         ESP_EARLY_LOGI(HPM_TAG, "Enabling flash high speed mode by %s", chip_hpm->method);
312         chip_hpm->flash_hpm_enable();
313         ESP_EARLY_LOGD(HPM_TAG, "Checking whether HPM has been executed");
314 
315         if (chip_hpm->flash_hpf_check() != ESP_OK) {
316             ESP_EARLY_LOGE(HPM_TAG, "Flash high performance mode hasn't been executed successfully");
317             return ESP_FAIL;
318         }
319         hpm_dummy_changed = (hpm_requirement_check == SPI_FLASH_HPM_DUMMY_NEEDED) ? true : false;
320     } else if (hpm_requirement_check == SPI_FLASH_HPM_BEYOND_LIMIT) {
321         ESP_EARLY_LOGE(HPM_TAG, "Flash does not have the ability to raise to that frequency");
322         return ESP_FAIL;
323     }
324     return ESP_OK;
325 }
326 
spi_flash_hpm_get_dummy(void)327 const spi_flash_hpm_dummy_conf_t *spi_flash_hpm_get_dummy(void)
328 {
329     chip_hpm->flash_get_dummy(&dummy_conf);
330     return &dummy_conf;
331 }
332 
spi_flash_hpm_dummy_adjust(void)333 bool spi_flash_hpm_dummy_adjust(void)
334 {
335     return hpm_dummy_changed;
336 }
337