1 /*
2 * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include "esp_efuse.h"
8 #include "esp_efuse_utility.h"
9 #include "soc/efuse_periph.h"
10 #include "assert.h"
11 #include "sdkconfig.h"
12 #include "esp_efuse_table.h"
13
14 const static char *TAG = "efuse";
15
16 #if defined(BOOTLOADER_BUILD)
17 #define EFUSE_LOCK_ACQUIRE_RECURSIVE()
18 #define EFUSE_LOCK_RELEASE_RECURSIVE()
19 #else
20 #include <string.h>
21 #include <zephyr/kernel.h>
22 K_MUTEX_DEFINE(s_efuse_lock);
23 #define EFUSE_LOCK_ACQUIRE_RECURSIVE() k_mutex_lock(&s_efuse_lock, K_FOREVER)
24 #define EFUSE_LOCK_RELEASE_RECURSIVE() k_mutex_unlock(&s_efuse_lock)
25
26 #endif
27
28 static int s_batch_writing_mode = 0;
29
30 // Public API functions
31
32 // read value from EFUSE, writing it into an array
esp_efuse_read_field_blob(const esp_efuse_desc_t * field[],void * dst,size_t dst_size_bits)33 esp_err_t esp_efuse_read_field_blob(const esp_efuse_desc_t* field[], void* dst, size_t dst_size_bits)
34 {
35 esp_err_t err = ESP_OK;
36 if (field == NULL || dst == NULL || dst_size_bits == 0) {
37 err = ESP_ERR_INVALID_ARG;
38 } else {
39 do {
40 memset((uint8_t *)dst, 0, esp_efuse_utility_get_number_of_items(dst_size_bits, 8));
41 err = esp_efuse_utility_process(field, dst, dst_size_bits, esp_efuse_utility_fill_buff);
42 #ifndef BOOTLOADER_BUILD
43 if (err == ESP_ERR_DAMAGED_READING) {
44 esp_rom_delay_us(1000);
45 }
46 #endif // BOOTLOADER_BUILD
47 } while (err == ESP_ERR_DAMAGED_READING);
48 }
49 return err;
50 }
51
esp_efuse_read_field_bit(const esp_efuse_desc_t * field[])52 bool esp_efuse_read_field_bit(const esp_efuse_desc_t *field[])
53 {
54 uint8_t value = 0;
55 esp_err_t err = esp_efuse_read_field_blob(field, &value, 1);
56 assert(err == ESP_OK);
57 return (err == ESP_OK) && value;
58 }
59
60 // read number of bits programmed as "1" in the particular field
esp_efuse_read_field_cnt(const esp_efuse_desc_t * field[],size_t * out_cnt)61 esp_err_t esp_efuse_read_field_cnt(const esp_efuse_desc_t* field[], size_t* out_cnt)
62 {
63 esp_err_t err = ESP_OK;
64 if (field == NULL || out_cnt == NULL) {
65 err = ESP_ERR_INVALID_ARG;
66 } else {
67 do {
68 *out_cnt = 0;
69 err = esp_efuse_utility_process(field, out_cnt, 0, esp_efuse_utility_count_once);
70 #ifndef BOOTLOADER_BUILD
71 if (err == ESP_ERR_DAMAGED_READING) {
72 esp_rom_delay_us(1000);
73 }
74 #endif // BOOTLOADER_BUILD
75 } while (err == ESP_ERR_DAMAGED_READING);
76 }
77 return err;
78 }
79
80 // write array to EFUSE
esp_efuse_write_field_blob(const esp_efuse_desc_t * field[],const void * src,size_t src_size_bits)81 esp_err_t esp_efuse_write_field_blob(const esp_efuse_desc_t* field[], const void* src, size_t src_size_bits)
82 {
83 EFUSE_LOCK_ACQUIRE_RECURSIVE();
84 esp_err_t err = ESP_OK;
85 if (field == NULL || src == NULL || src_size_bits == 0) {
86 err = ESP_ERR_INVALID_ARG;
87 } else {
88 if (s_batch_writing_mode == 0) {
89 esp_efuse_utility_reset();
90 }
91 err = esp_efuse_utility_process(field, (void*)src, src_size_bits, esp_efuse_utility_write_blob);
92
93 if (s_batch_writing_mode == 0) {
94 if (err == ESP_OK) {
95 err = esp_efuse_utility_apply_new_coding_scheme();
96 if (err == ESP_OK) {
97 err = esp_efuse_utility_burn_efuses();
98 }
99 }
100 esp_efuse_utility_reset();
101 }
102 }
103 EFUSE_LOCK_RELEASE_RECURSIVE();
104 return err;
105 }
106
107 // program cnt bits to "1"
esp_efuse_write_field_cnt(const esp_efuse_desc_t * field[],size_t cnt)108 esp_err_t esp_efuse_write_field_cnt(const esp_efuse_desc_t* field[], size_t cnt)
109 {
110 EFUSE_LOCK_ACQUIRE_RECURSIVE();
111 esp_err_t err = ESP_OK;
112 if (field == NULL || cnt == 0) {
113 err = ESP_ERR_INVALID_ARG;
114 } else {
115 if (s_batch_writing_mode == 0) {
116 esp_efuse_utility_reset();
117 }
118 err = esp_efuse_utility_process(field, &cnt, 0, esp_efuse_utility_write_cnt);
119
120 if (cnt != 0) {
121 ESP_LOGE(TAG, "The required number of bits can not be set. [Not set %d]", cnt);
122 err = ESP_ERR_EFUSE_CNT_IS_FULL;
123 }
124 if (err == ESP_OK_EFUSE_CNT) {
125 err = ESP_OK;
126 }
127
128 if (s_batch_writing_mode == 0) {
129 if (err == ESP_OK) {
130 err = esp_efuse_utility_apply_new_coding_scheme();
131 if (err == ESP_OK) {
132 err = esp_efuse_utility_burn_efuses();
133 }
134 }
135 esp_efuse_utility_reset();
136 }
137 }
138 EFUSE_LOCK_RELEASE_RECURSIVE();
139 return err;
140 }
141
esp_efuse_write_field_bit(const esp_efuse_desc_t * field[])142 esp_err_t esp_efuse_write_field_bit(const esp_efuse_desc_t* field[])
143 {
144 esp_err_t err;
145 uint8_t existing = 0;
146 const uint8_t one = 1;
147
148 if (field == NULL || field[0]->bit_count != 1) {
149 return ESP_ERR_INVALID_ARG;
150 }
151
152 /* Check existing value. esp_efuse_write_field_blob() also checks this, but will log an error */
153 err = esp_efuse_read_field_blob(field, &existing, 1);
154 if (err != ESP_OK || existing) {
155 return err; // Error reading, or the bit is already written and we can no-op this
156 }
157
158 return esp_efuse_write_field_blob(field, &one, 1);
159 }
160
161 // get the length of the field in bits
esp_efuse_get_field_size(const esp_efuse_desc_t * field[])162 int esp_efuse_get_field_size(const esp_efuse_desc_t* field[])
163 {
164 int bits_counter = 0;
165 if (field != NULL) {
166 int i = 0;
167 while (field[i] != NULL) {
168 bits_counter += field[i]->bit_count;
169 ++i;
170 }
171 }
172 return bits_counter;
173 }
174
175 // reading efuse register.
esp_efuse_read_reg(esp_efuse_block_t blk,unsigned int num_reg)176 uint32_t esp_efuse_read_reg(esp_efuse_block_t blk, unsigned int num_reg)
177 {
178 uint32_t ret_val = 0;
179 esp_err_t err = esp_efuse_read_block(blk, &ret_val, num_reg * 32, 32);
180 assert(err == ESP_OK);
181 (void)err;
182 return ret_val;
183 }
184
185 // writing efuse register.
esp_efuse_write_reg(esp_efuse_block_t blk,unsigned int num_reg,uint32_t val)186 esp_err_t esp_efuse_write_reg(esp_efuse_block_t blk, unsigned int num_reg, uint32_t val)
187 {
188 EFUSE_LOCK_ACQUIRE_RECURSIVE();
189 if (s_batch_writing_mode == 0) {
190 esp_efuse_utility_reset();
191 }
192 esp_err_t err = esp_efuse_utility_write_reg(blk, num_reg, val);
193 if (s_batch_writing_mode == 0) {
194 if (err == ESP_OK) {
195 err = esp_efuse_utility_apply_new_coding_scheme();
196 if (err == ESP_OK) {
197 err = esp_efuse_utility_burn_efuses();
198 }
199 }
200 esp_efuse_utility_reset();
201 }
202 EFUSE_LOCK_RELEASE_RECURSIVE();
203 return err;
204 }
205
206 // This function reads the key from the efuse block, starting at the offset and the required size.
esp_efuse_read_block(esp_efuse_block_t blk,void * dst_key,size_t offset_in_bits,size_t size_bits)207 esp_err_t esp_efuse_read_block(esp_efuse_block_t blk, void* dst_key, size_t offset_in_bits, size_t size_bits)
208 {
209 esp_err_t err = ESP_OK;
210 if (blk == EFUSE_BLK0 || blk >= EFUSE_BLK_MAX || dst_key == NULL || size_bits == 0) {
211 err = ESP_ERR_INVALID_ARG;
212 } else {
213 const esp_efuse_desc_t field_desc[] = {
214 {blk, offset_in_bits, size_bits},
215 };
216
217 const esp_efuse_desc_t* field[] = {
218 &field_desc[0],
219 NULL
220 };
221 err = esp_efuse_read_field_blob(field, dst_key, size_bits);
222 }
223 return err;
224 }
225
226 // This function writes the key from the efuse block, starting at the offset and the required size.
esp_efuse_write_block(esp_efuse_block_t blk,const void * src_key,size_t offset_in_bits,size_t size_bits)227 esp_err_t esp_efuse_write_block(esp_efuse_block_t blk, const void* src_key, size_t offset_in_bits, size_t size_bits)
228 {
229 esp_err_t err = ESP_OK;
230 if (blk == EFUSE_BLK0 || blk >= EFUSE_BLK_MAX || src_key == NULL || size_bits == 0) {
231 err = ESP_ERR_INVALID_ARG;
232 } else {
233 const esp_efuse_desc_t field_desc[] = {
234 {blk, offset_in_bits, size_bits},
235 };
236
237 const esp_efuse_desc_t* field[] = {
238 &field_desc[0],
239 NULL
240 };
241 err = esp_efuse_write_field_blob(field, src_key, size_bits);
242 }
243 return err;
244 }
245
esp_efuse_batch_write_begin(void)246 esp_err_t esp_efuse_batch_write_begin(void)
247 {
248 EFUSE_LOCK_ACQUIRE_RECURSIVE();
249 assert(s_batch_writing_mode >= 0);
250 if (++s_batch_writing_mode == 1) {
251 esp_efuse_utility_reset();
252 ESP_LOGI(TAG, "Batch mode of writing fields is enabled");
253 };
254 return ESP_OK;
255 }
256
esp_efuse_batch_write_cancel(void)257 esp_err_t esp_efuse_batch_write_cancel(void)
258 {
259 if (s_batch_writing_mode == 0) {
260 ESP_LOGE(TAG, "Batch mode was not enabled");
261 return ESP_ERR_INVALID_STATE;
262 }
263 if (--s_batch_writing_mode == 0) {
264 esp_efuse_utility_reset();
265 ESP_LOGI(TAG, "Batch mode of writing fields is cancelled");
266 EFUSE_LOCK_RELEASE_RECURSIVE();
267 }
268 return ESP_OK;
269 }
270
esp_efuse_batch_write_commit(void)271 esp_err_t esp_efuse_batch_write_commit(void)
272 {
273 if (s_batch_writing_mode == 0) {
274 ESP_LOGE(TAG, "Batch mode was not enabled");
275 return ESP_ERR_INVALID_STATE;
276 }
277 if (--s_batch_writing_mode == 0) {
278 esp_err_t err = esp_efuse_utility_apply_new_coding_scheme();
279 if (err == ESP_OK) {
280 err = esp_efuse_utility_burn_efuses();
281 ESP_LOGI(TAG, "Batch mode. Prepared fields are committed");
282 } else {
283 esp_efuse_utility_reset();
284 }
285 EFUSE_LOCK_RELEASE_RECURSIVE();
286 return err;
287 }
288 return ESP_OK;
289 }
290
esp_efuse_check_errors(void)291 esp_err_t esp_efuse_check_errors(void)
292 {
293 return esp_efuse_utility_check_errors();
294 }
295