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