1 /*
2  * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdint.h>
8 #include <stdbool.h>
9 #include "sdkconfig.h"
10 #include "esp_err.h"
11 #include "esp_log.h"
12 #include "spi_flash_defs.h"
13 #include "esp_rom_sys.h"
14 #include "esp_rom_spiflash.h"
15 #include "spi_flash_override.h"
16 #include "esp_private/spi_flash_os.h"
17 
18 // TODO: These dependencies will be removed after remove bootloader_flash to G0.IDF-4609
19 #include "bootloader_flash_override.h"
20 #include "bootloader_flash_priv.h"
21 
22 /***********************************************************************************
23  * Flash wrap feature (also called burst read on some flash chips)
24  *
25  * Different flash chips enter wrap (burst read) mode in different strategies.
26  * 1. Command 0xC0 + 8 Bytes.
27  * 2. Command 0x77 + 24 dummy + 8 Bytes.
28  **********************************************************************************/
29 
30 #if SOC_SPI_MEM_SUPPORT_WRAP
31 
32 const static char *FLASH_WRAP_TAG = "flash wrap";
33 
34 // TODO: This function will be changed after remove bootloader_flash to G0.IDF-4609
35 extern uint32_t bootloader_flash_execute_command_common(
36     uint8_t command,
37     uint32_t addr_len, uint32_t address,
38     uint8_t dummy_len,
39     uint8_t mosi_len, uint32_t mosi_data,
40     uint8_t miso_len);
41 
spi_flash_wrap_probe_c0(uint32_t flash_id)42 esp_err_t spi_flash_wrap_probe_c0(uint32_t flash_id)
43 {
44     esp_err_t ret = ESP_OK;
45 
46     switch (flash_id) {
47     /* The flash listed here should enter the wrap with command 0xC0 */
48     case 0xC22018:
49         break;
50     default:
51         ret = ESP_ERR_NOT_FOUND;
52         break;
53     }
54     return ret;
55 }
56 
57 /**
58  * @brief Burst read with command 0xC0 + 8 Bytes
59  *
60  * |------------|-----------------------------|
61  * |    data    |         wrap depth          |
62  * |     00h    |             8               |
63  * |     01h    |             16              |
64  * |     02h    |             32              |
65  * |     03h    |             64              |
66  * |------------|-----------------------------|
67  */
spi_flash_wrap_enable_c0(spi_flash_wrap_size_t wrap_size)68 esp_err_t spi_flash_wrap_enable_c0(spi_flash_wrap_size_t wrap_size)
69 {
70     uint8_t wrap_code = (uint8_t) (__builtin_ctz(wrap_size) - 3);
71     bootloader_flash_execute_command_common(CMD_BURST_RD, 0, 0, 0, 8, wrap_code, 0);
72     return ESP_OK;
73 }
74 
75 /**
76  * @brief Burst read with command 0x77 + 24 Dummy + 8 Bytes
77  *
78  * |-------------------|-----------------------------|
79  * |    data(W6,W5)    |         wrap depth          |
80  * |        00h        |             8               |
81  * |        01h        |             16              |
82  * |        02h        |             32              |
83  * |        03h        |             64              |
84  * |-------------------|-----------------------------|
85  */
spi_flash_wrap_enable_77(spi_flash_wrap_size_t wrap_size)86 esp_err_t spi_flash_wrap_enable_77(spi_flash_wrap_size_t wrap_size)
87 {
88     uint8_t wrap_code = (uint8_t) (((__builtin_ctz(wrap_size) - 3) * 2) << 4);
89     // According to the special format, we need enable QIO_FWRITE for command 77h and clear it after this command is done.
90     REG_SET_BIT(SPI_MEM_USER_REG(1), SPI_MEM_FWRITE_QIO);
91     bootloader_flash_execute_command_common(CMD_WRAP, 0, 0, 6, 8, wrap_code, 0);
92     REG_CLR_BIT(SPI_MEM_USER_REG(1), SPI_MEM_FWRITE_QIO);
93     return ESP_OK;
94 }
95 
96 /**
97  * @brief Burst read is cleared by setting 0x1xh,
98  *        so we set 0x10 to disable this feature.
99  */
spi_flash_wrap_clear_c0(void)100 esp_err_t spi_flash_wrap_clear_c0(void)
101 {
102     bootloader_flash_execute_command_common(CMD_BURST_RD, 0, 0, 0, 8, 0x10, 0);
103     return ESP_OK;
104 }
105 
106 /**
107  * @brief Burst read is cleared by setting W4 bit 1,
108  *        so we set 0x10 to disable this feature.
109  */
spi_flash_wrap_clear_77(void)110 esp_err_t spi_flash_wrap_clear_77(void)
111 {
112     // According to the special format, we need enable QIO_FWRITE for command 77h and clear it after this command is done.
113     REG_SET_BIT(SPI_MEM_USER_REG(1), SPI_MEM_FWRITE_QIO);
114     bootloader_flash_execute_command_common(CMD_WRAP, 0, 0, 6, 8, 0x10, 0);
115     REG_CLR_BIT(SPI_MEM_USER_REG(1), SPI_MEM_FWRITE_QIO);
116     return ESP_OK;
117 }
118 
119 const spi_flash_wrap_info_t __attribute__((weak)) spi_flash_wrap_list[] = {
120     /* method                probe                 chip wrap set              chip wrap clear  */
121     {"C0H+8B",     spi_flash_wrap_probe_c0,     spi_flash_wrap_enable_c0, spi_flash_wrap_clear_c0},
122     {"default",        NULL,                    spi_flash_wrap_enable_77, spi_flash_wrap_clear_77},
123 };
124 
125 static const spi_flash_wrap_info_t *chip_wrap = NULL;
126 
spi_flash_wrap_probe(void)127 esp_err_t spi_flash_wrap_probe(void)
128 {
129     uint32_t flash_chip_id = g_rom_flashchip.device_id;
130     const spi_flash_wrap_info_t *chip = spi_flash_wrap_list;
131     esp_err_t ret = ESP_OK;
132     while (chip->probe) {
133         ret = chip->probe(flash_chip_id);
134         if (ret == ESP_OK) {
135             break;
136         }
137         chip++;
138     }
139     chip_wrap = chip;
140     return ret;
141 }
142 
spi_flash_wrap_enable(spi_flash_wrap_size_t wrap_size)143 esp_err_t spi_flash_wrap_enable(spi_flash_wrap_size_t wrap_size)
144 {
145     return chip_wrap->chip_wrap_set(wrap_size);
146 }
147 
spi_flash_wrap_disable(void)148 esp_err_t spi_flash_wrap_disable(void)
149 {
150     return chip_wrap->chip_wrap_clr();
151 }
152 
spi_flash_support_wrap_size(uint32_t wrap_size)153 bool spi_flash_support_wrap_size(uint32_t wrap_size)
154 {
155     // Only QIO mode supports wrap.
156     if (!REG_GET_BIT(SPI_MEM_CTRL_REG(0), SPI_MEM_FREAD_QIO)) {
157         ESP_EARLY_LOGE(FLASH_WRAP_TAG, "flash wrap is only supported in QIO mode");
158         abort();
159     }
160     // Only following size can be wrapped.
161     switch (wrap_size) {
162     case 0:
163     case 8:
164     case 16:
165     case 32:
166     case 64:
167         return true;
168     default:
169         return false;
170     }
171 }
172 
173 #endif // SOC_SPI_MEM_SUPPORT_WRAP
174