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