1
6
7
15
16
17
18
19
20
21
22
23
29
30
31
32
33
39
40
41
59
60
61
65
66
70
71
72
76
77
78
79
80
81
93
94
95
96
97
98
99
100
101
102
108
111
117
118
119
120
133
134
135
136
137
138
139
142
143
144
145
146
147
148
149
150
153
154
155
159
160
161
162
165
169
170
171
172
173
174
175
176
177
178
181
182
183
184
185
186
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
214
215
222
223
224
225
/* ... */
#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
const esp_efuse_range_addr_t range_read_addr_blocks[] = {
{EFUSE_BLK0_RDATA0_REG, EFUSE_BLK0_RDATA6_REG},
{EFUSE_BLK1_RDATA0_REG, EFUSE_BLK1_RDATA7_REG},
{EFUSE_BLK2_RDATA0_REG, EFUSE_BLK2_RDATA7_REG},
{EFUSE_BLK3_RDATA0_REG, EFUSE_BLK3_RDATA7_REG}
}{...};
static uint32_t write_mass_blocks[EFUSE_BLK_MAX][COUNT_EFUSE_REG_PER_BLOCK] = { 0 };
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
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);
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/* ... */
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;
}{ ... }
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
if (esp_efuse_set_timing() != ESP_OK) {
ESP_LOGE(TAG, "Efuse fields are not burnt");
}{...} else {
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) {
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);
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/* ... */
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);
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/* ... */
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);
}{...}
}{ ... }
esp_err_t esp_efuse_utility_apply_new_coding_scheme()
{
uint8_t buf_r_data[COUNT_EFUSE_REG_PER_BLOCK * 4];
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;
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;
}{ ... }