Select one of the symbols to view example projects that use it.
 
Outline
#include "esp_efuse_utility.h"
#include "soc/efuse_periph.h"
#include "hal/efuse_hal.h"
#include "esp_private/esp_clk.h"
#include "esp_log.h"
#include "assert.h"
#include "sdkconfig.h"
#include <sys/param.h>
TAG
range_read_addr_blocks
write_mass_blocks
range_write_addr_blocks
start_write_addr
esp_efuse_set_timing()
esp_efuse_utility_clear_program_registers()
esp_efuse_utility_check_errors()
esp_efuse_utility_burn_chip()
esp_efuse_utility_burn_chip_opt(bool, bool)
esp_efuse_utility_apply_34_encoding(const uint8_t *, uint32_t *, size_t)
apply_repeat_encoding(const uint8_t *, uint32_t *, size_t)
read_r_data(esp_efuse_block_t, uint32_t *)
esp_efuse_utility_apply_new_coding_scheme()
Files
loading...
SourceVuESP-IDF Framework and ExamplesESP-IDFcomponents/efuse/esp32/esp_efuse_utility.c
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/* * SPDX-FileCopyrightText: 2017-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 *//* ... */ #include "esp_efuse_utility.h" #include "soc/efuse_periph.h" #include "hal/efuse_hal.h" #include "esp_private/esp_clk.h" #include "esp_log.h" #include "assert.h" #include "sdkconfig.h" #include <sys/param.h>8 includes static const char *TAG = "efuse"; #ifdef CONFIG_EFUSE_VIRTUAL extern uint32_t virt_blocks[EFUSE_BLK_MAX][COUNT_EFUSE_REG_PER_BLOCK]; #endif // CONFIG_EFUSE_VIRTUAL /*Range addresses to read blocks*/ const esp_efuse_range_addr_t range_read_addr_blocks[] = { {EFUSE_BLK0_RDATA0_REG, EFUSE_BLK0_RDATA6_REG}, // range address of EFUSE_BLK0 {EFUSE_BLK1_RDATA0_REG, EFUSE_BLK1_RDATA7_REG}, // range address of EFUSE_BLK1 {EFUSE_BLK2_RDATA0_REG, EFUSE_BLK2_RDATA7_REG}, // range address of EFUSE_BLK2 {EFUSE_BLK3_RDATA0_REG, EFUSE_BLK3_RDATA7_REG} // range address of EFUSE_BLK3 }{...}; static uint32_t write_mass_blocks[EFUSE_BLK_MAX][COUNT_EFUSE_REG_PER_BLOCK] = { 0 }; /*Range addresses to write blocks (it is not real regs, it is a buffer) */ const esp_efuse_range_addr_t range_write_addr_blocks[] = { {(uint32_t) &write_mass_blocks[EFUSE_BLK0][0], (uint32_t) &write_mass_blocks[EFUSE_BLK0][6]}, {(uint32_t) &write_mass_blocks[EFUSE_BLK1][0], (uint32_t) &write_mass_blocks[EFUSE_BLK1][7]}, {(uint32_t) &write_mass_blocks[EFUSE_BLK2][0], (uint32_t) &write_mass_blocks[EFUSE_BLK2][7]}, {(uint32_t) &write_mass_blocks[EFUSE_BLK3][0], (uint32_t) &write_mass_blocks[EFUSE_BLK3][7]}, }{...}; #ifndef CONFIG_EFUSE_VIRTUAL /* Addresses to write blocks*/ const uint32_t start_write_addr[] = { EFUSE_BLK0_WDATA0_REG, EFUSE_BLK1_WDATA0_REG, EFUSE_BLK2_WDATA0_REG, EFUSE_BLK3_WDATA0_REG, }{...}; static void apply_repeat_encoding(const uint8_t *in_bytes, uint32_t *out_words, size_t in_bytes_len); // Update Efuse timing configuration static esp_err_t esp_efuse_set_timing(void) { uint32_t apb_freq_mhz = esp_clk_apb_freq() / 1000000; efuse_hal_set_timing(apb_freq_mhz); return ESP_OK; }{ ... } #endif/* ... */ // ifndef CONFIG_EFUSE_VIRTUAL // Efuse read operation: copies data from physical efuses to efuse read registers. void esp_efuse_utility_clear_program_registers(void) { efuse_hal_clear_program_registers(); }{ ... } esp_err_t esp_efuse_utility_check_errors(void) { return ESP_OK; }{ ... } // Burn values written to the efuse write registers esp_err_t esp_efuse_utility_burn_chip(void) { return esp_efuse_utility_burn_chip_opt(false, true); }{ ... } esp_err_t esp_efuse_utility_burn_chip_opt(bool ignore_coding_errors, bool verify_written_data) { esp_err_t error = ESP_OK; #ifdef CONFIG_EFUSE_VIRTUAL (void) ignore_coding_errors; (void) verify_written_data; ESP_LOGW(TAG, "Virtual efuses enabled: Not really burning eFuses"); for (int num_block = EFUSE_BLK_MAX - 1; num_block >= EFUSE_BLK0; num_block--) { int subblock = 0; for (uint32_t addr_wr_block = range_write_addr_blocks[num_block].start; addr_wr_block <= range_write_addr_blocks[num_block].end; addr_wr_block += 4) { virt_blocks[num_block][subblock++] |= REG_READ(addr_wr_block); }{...} }{...} #ifdef CONFIG_EFUSE_VIRTUAL_KEEP_IN_FLASH esp_efuse_utility_write_efuses_to_flash(); #endif/* ... */ #else // CONFIG_EFUSE_VIRTUAL if (esp_efuse_set_timing() != ESP_OK) { ESP_LOGE(TAG, "Efuse fields are not burnt"); }{...} else { // Permanently update values written to the efuse write registers // It is necessary to process blocks in the order from MAX-> EFUSE_BLK0, because EFUSE_BLK0 has protection bits for other blocks. for (int num_block = EFUSE_BLK_MAX - 1; num_block >= EFUSE_BLK0; num_block--) { esp_efuse_coding_scheme_t scheme = esp_efuse_get_coding_scheme(num_block); bool need_burn_block = false; for (uint32_t addr_wr_block = range_write_addr_blocks[num_block].start; addr_wr_block <= range_write_addr_blocks[num_block].end; addr_wr_block += 4) { if (REG_READ(addr_wr_block) != 0) { need_burn_block = true; break; }{...} }{...} if (!need_burn_block) { continue; }{...} if (error) { // It is done for a use case: BLOCK2 (Flash encryption key) could have an error (incorrect written data) // in this case we can not burn any data into BLOCK0 because it might set read/write protections of BLOCK2. ESP_LOGE(TAG, "BLOCK%d can not be burned because a previous block got an error, skipped.", num_block); continue; }{...} efuse_hal_clear_program_registers(); unsigned w_data_len; unsigned r_data_len; if (scheme == EFUSE_CODING_SCHEME_3_4) { esp_efuse_utility_apply_34_encoding((void *)range_write_addr_blocks[num_block].start, (uint32_t *)start_write_addr[num_block], ESP_EFUSE_LEN_OF_3_4_SCHEME_BLOCK_IN_BYTES); r_data_len = ESP_EFUSE_LEN_OF_3_4_SCHEME_BLOCK_IN_BYTES; w_data_len = 32; }{...} else if (scheme == EFUSE_CODING_SCHEME_REPEAT) { apply_repeat_encoding((void *)range_write_addr_blocks[num_block].start, (uint32_t *)start_write_addr[num_block], 16); r_data_len = ESP_EFUSE_LEN_OF_REPEAT_BLOCK_IN_BYTES; w_data_len = 32; }{...} else { r_data_len = (range_read_addr_blocks[num_block].end - range_read_addr_blocks[num_block].start) + sizeof(uint32_t); w_data_len = (range_write_addr_blocks[num_block].end - range_write_addr_blocks[num_block].start) + sizeof(uint32_t); memcpy((void *)start_write_addr[num_block], (void *)range_write_addr_blocks[num_block].start, w_data_len); }{...} uint32_t backup_write_data[8]; memcpy(backup_write_data, (void *)start_write_addr[num_block], w_data_len); int repeat_burn_op = 1; bool correct_written_data; bool coding_error_before = !ignore_coding_errors && efuse_hal_is_coding_error_in_block(num_block); if (coding_error_before) { ESP_LOGW(TAG, "BLOCK%d already has a coding error", num_block); }{...} bool coding_error_occurred; do { ESP_LOGI(TAG, "BURN BLOCK%d", num_block); efuse_hal_program(0); // BURN a block bool coding_error_after = efuse_hal_is_coding_error_in_block(num_block); coding_error_occurred = !ignore_coding_errors && (coding_error_before != coding_error_after) && !coding_error_before; if (coding_error_occurred) { ESP_LOGW(TAG, "BLOCK%d got a coding error", num_block); }{...} correct_written_data = (verify_written_data) ? esp_efuse_utility_is_correct_written_data(num_block, r_data_len) : true; if (!correct_written_data || coding_error_occurred) { ESP_LOGW(TAG, "BLOCK%d: next retry to fix an error [%d/3]...", num_block, repeat_burn_op); memcpy((void *)start_write_addr[num_block], (void *)backup_write_data, w_data_len); }{...} }{...} while ((!correct_written_data || coding_error_occurred) && repeat_burn_op++ < 3); if (coding_error_occurred) { ESP_LOGW(TAG, "Coding error was not fixed"); }{...} if (!correct_written_data) { ESP_LOGE(TAG, "Written data are incorrect"); error = ESP_FAIL; }{...} }{...} }{...} #endif/* ... */ // CONFIG_EFUSE_VIRTUAL esp_efuse_utility_reset(); return error; }{ ... } esp_err_t esp_efuse_utility_apply_34_encoding(const uint8_t *in_bytes, uint32_t *out_words, size_t in_bytes_len) { if (in_bytes == NULL || out_words == NULL || in_bytes_len % 6 != 0) { return ESP_ERR_INVALID_ARG; }{...} while (in_bytes_len > 0) { uint8_t out[8]; uint8_t xor = 0; uint8_t mul = 0; for (int i = 0; i < 6; i++) { xor ^= in_bytes[i]; mul += (i + 1) * __builtin_popcount(in_bytes[i]); }{...} memcpy(out, in_bytes, 6); // Data bytes out[6] = xor; out[7] = mul; memcpy(out_words, out, 8); in_bytes_len -= 6; in_bytes += 6; out_words += 2; }{...} return ESP_OK; }{ ... } #ifndef CONFIG_EFUSE_VIRTUAL static void apply_repeat_encoding(const uint8_t *in_bytes, uint32_t *out_words, size_t in_bytes_len) { for (unsigned i = 0; i < 2; i++) { memcpy(&out_words[i * 4], (uint32_t *)in_bytes, in_bytes_len); }{...} }{ ... } #endif/* ... */ // CONFIG_EFUSE_VIRTUAL static void read_r_data(esp_efuse_block_t num_block, uint32_t* buf_r_data) { int i = 0; for (uint32_t addr_rd_block = range_read_addr_blocks[num_block].start; addr_rd_block <= range_read_addr_blocks[num_block].end; addr_rd_block += 4, ++i) { buf_r_data[i] = esp_efuse_utility_read_reg(num_block, i); }{...} }{ ... } // This function just checkes that given data for blocks will not rise a coding issue during the burn operation. // Encoded data will be set during the burn operation. esp_err_t esp_efuse_utility_apply_new_coding_scheme() { uint8_t buf_r_data[COUNT_EFUSE_REG_PER_BLOCK * 4]; // start with EFUSE_BLK1. EFUSE_BLK0 - always uses EFUSE_CODING_SCHEME_NONE. for (int num_block = EFUSE_BLK1; num_block < EFUSE_BLK_MAX; num_block++) { esp_efuse_coding_scheme_t scheme = esp_efuse_get_coding_scheme(num_block); if (scheme != EFUSE_CODING_SCHEME_NONE) { bool is_write_data = false; for (uint32_t addr_wr_block = range_write_addr_blocks[num_block].start; addr_wr_block <= range_write_addr_blocks[num_block].end; addr_wr_block += 4) { if (REG_READ(addr_wr_block)) { is_write_data = true; break; }{...} }{...} if (is_write_data) { read_r_data(num_block, (uint32_t*)buf_r_data); uint8_t* buf_w_data = (uint8_t*)range_write_addr_blocks[num_block].start; if (scheme == EFUSE_CODING_SCHEME_3_4) { if (*((uint32_t*)buf_w_data + 6) != 0 || *((uint32_t*)buf_w_data + 7) != 0) { return ESP_ERR_CODING; }{...} for (int i = 0; i < ESP_EFUSE_LEN_OF_3_4_SCHEME_BLOCK_IN_BYTES; ++i) { if (buf_w_data[i] != 0) { int st_offset_buf = (i / 6) * 6; // check that place is free. for (int n = st_offset_buf; n < st_offset_buf + 6; ++n) { if (buf_r_data[n] != 0) { ESP_LOGE(TAG, "Bits are not empty. Write operation is forbidden."); return ESP_ERR_CODING; }{...} }{...} }{...} }{...} }{...} else if (scheme == EFUSE_CODING_SCHEME_REPEAT) { for (int i = 4; i < 8; ++i) { if (*((uint32_t*)buf_w_data + i) != 0) { return ESP_ERR_CODING; }{...} }{...} }{...} }{...} }{...} }{...} return ESP_OK; }{ ... }
Details
Show:
from
Types: Columns:
This file uses the notable symbols shown below. Click anywhere in the file to view more details.