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