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