• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "esp_efuse_utility.h"
16 
17 #include "soc/efuse_periph.h"
18 #include "esp_log.h"
19 #include "assert.h"
20 #include "sdkconfig.h"
21 #include <sys/param.h>
22 
23 static const char *TAG = "efuse";
24 
25 // Array for emulate efuse registers.
26 #ifdef CONFIG_EFUSE_VIRTUAL
27 uint32_t virt_blocks[EFUSE_BLK_MAX][COUNT_EFUSE_REG_PER_BLOCK];
28 
29 /* Call the update function to seed virtual efuses during initialization */
30 __attribute__((constructor)) void esp_efuse_utility_update_virt_blocks(void);
31 #endif
32 
33 extern const esp_efuse_range_addr_t range_read_addr_blocks[];
34 extern const esp_efuse_range_addr_t range_write_addr_blocks[];
35 
36 static int get_reg_num(int bit_start, int bit_count, int i_reg);
37 static int get_starting_bit_num_in_reg(int bit_start, int i_reg);
38 static uint32_t get_mask(unsigned int bit_count, unsigned int shift);
39 static int get_count_bits_in_reg(int bit_start, int bit_count, int i_reg);
40 static void write_reg(esp_efuse_block_t blk, unsigned int num_reg, uint32_t value);
41 static uint32_t fill_reg(int bit_start_in_reg, int bit_count_in_reg, uint8_t* blob, int* filled_bits_blob);
42 static uint32_t set_cnt_in_reg(int bit_start_in_reg, int bit_count_used_in_reg, uint32_t reg_masked, size_t* cnt);
43 static bool check_range_of_bits(esp_efuse_block_t blk, int offset_in_bits, int size_bits);
44 
45 // This function processes the field by calling the passed function.
esp_efuse_utility_process(const esp_efuse_desc_t * field[],void * ptr,size_t ptr_size_bits,efuse_func_proc_t func_proc)46 esp_err_t esp_efuse_utility_process(const esp_efuse_desc_t* field[], void* ptr, size_t ptr_size_bits, efuse_func_proc_t func_proc)
47 {
48     esp_err_t err = ESP_OK;
49     int bits_counter = 0;
50 
51     // get and check size.
52     int field_len = esp_efuse_get_field_size(field);
53     int req_size = (ptr_size_bits == 0) ? field_len : MIN(ptr_size_bits, field_len);
54 
55     int i = 0;
56     while (err == ESP_OK && req_size > bits_counter && field[i] != NULL) {
57         if (check_range_of_bits(field[i]->efuse_block, field[i]->bit_start, field[i]->bit_count) == false) {
58             ESP_EARLY_LOGE(TAG, "Range of data does not match the coding scheme");
59             err = ESP_ERR_CODING;
60         }
61         int i_reg = 0;
62         int num_reg;
63         while (err == ESP_OK && req_size > bits_counter &&
64                 (num_reg = get_reg_num(field[i]->bit_start, field[i]->bit_count, i_reg)) != -1) {
65 
66             int start_bit = get_starting_bit_num_in_reg(field[i]->bit_start, i_reg);
67             int num_bits = get_count_bits_in_reg(field[i]->bit_start, field[i]->bit_count, i_reg);
68             if ((bits_counter + num_bits) > req_size) { // Limits the length of the field.
69                 num_bits = req_size - bits_counter;
70             }
71             ESP_EARLY_LOGD(TAG, "In EFUSE_BLK%d__DATA%d_REG is used %d bits starting with %d bit",
72                     (int)field[i]->efuse_block, num_reg, num_bits, start_bit);
73             err = func_proc(num_reg, field[i]->efuse_block, start_bit, num_bits, ptr, &bits_counter);
74             ++i_reg;
75         }
76         i++;
77     }
78     assert(bits_counter <= req_size);
79     return err;
80 }
81 
82 
83 // Read efuse register and write this value to array.
esp_efuse_utility_fill_buff(unsigned int num_reg,esp_efuse_block_t efuse_block,int bit_start,int bit_count,void * arr_out,int * bits_counter)84 esp_err_t esp_efuse_utility_fill_buff(unsigned int num_reg, esp_efuse_block_t efuse_block, int bit_start, int bit_count, void* arr_out, int* bits_counter)
85 {
86     uint8_t* blob = (uint8_t *) arr_out;
87     uint32_t reg = esp_efuse_utility_read_reg(efuse_block, num_reg);
88     uint64_t reg_of_aligned_bits = (reg >> bit_start) & get_mask(bit_count, 0);
89 
90     int shift_bit = (*bits_counter) % 8;
91     if (shift_bit != 0) {
92         blob[(*bits_counter) / 8] |= (uint8_t)(reg_of_aligned_bits << shift_bit);
93         shift_bit = ((8 - shift_bit) < bit_count) ? (8 - shift_bit) : bit_count;
94         (*bits_counter) += shift_bit;
95         bit_count -= shift_bit;
96     }
97 
98     int sum_shift = 0;
99     while (bit_count > 0) {
100         sum_shift += shift_bit;
101         blob[(*bits_counter) / 8] |= (uint8_t)(reg_of_aligned_bits >> sum_shift);
102         shift_bit = (bit_count > 8) ? 8 : bit_count;
103         (*bits_counter) += shift_bit;
104         bit_count -= shift_bit;
105     };
106     return ESP_OK;
107 }
108 
109 // Count a set bits.
esp_efuse_utility_count_once(unsigned int num_reg,esp_efuse_block_t efuse_block,int bit_start,int bit_count,void * out_cnt,int * bits_counter)110 esp_err_t esp_efuse_utility_count_once(unsigned int num_reg, esp_efuse_block_t efuse_block, int bit_start, int bit_count, void* out_cnt, int* bits_counter)
111 {
112     uint32_t reg = esp_efuse_utility_read_reg(efuse_block, num_reg);
113     *((size_t *)out_cnt) += __builtin_popcount(reg & get_mask(bit_count, bit_start)); // Returns the number of 1-bits in reg.
114     *bits_counter += bit_count;
115     return ESP_OK;
116 }
117 
118 // Fill registers from array for writing.
esp_efuse_utility_write_blob(unsigned int num_reg,esp_efuse_block_t efuse_block,int bit_start,int bit_count,void * arr_in,int * bits_counter)119 esp_err_t esp_efuse_utility_write_blob(unsigned int num_reg, esp_efuse_block_t efuse_block, int bit_start, int bit_count, void* arr_in, int* bits_counter)
120 {
121     uint32_t reg_to_write = fill_reg(bit_start, bit_count, (uint8_t *)arr_in, bits_counter);
122     return esp_efuse_utility_write_reg(efuse_block, num_reg, reg_to_write);
123 }
124 
125 // fill registers with the required number of bits for writing.
esp_efuse_utility_write_cnt(unsigned int num_reg,esp_efuse_block_t efuse_block,int bit_start,int bit_count,void * cnt,int * bits_counter)126 esp_err_t esp_efuse_utility_write_cnt(unsigned int num_reg, esp_efuse_block_t efuse_block, int bit_start, int bit_count, void* cnt, int* bits_counter)
127 {
128     esp_err_t err = ESP_OK;
129     uint32_t reg = esp_efuse_utility_read_reg(efuse_block, num_reg);
130     size_t* set_bits = (size_t*)cnt;
131     uint32_t mask = get_mask(bit_count, bit_start);
132     uint32_t reg_masked_bits = reg & mask;
133     if ((reg_masked_bits ^ mask) != 0) {// register has free bits to set them to 1?
134         uint32_t reg_to_write = set_cnt_in_reg(bit_start, bit_count, reg_masked_bits, set_bits);
135         write_reg(efuse_block, num_reg, reg_to_write);
136     }
137     *bits_counter += bit_count;
138     if ((*set_bits) == 0) {
139         err = ESP_OK_EFUSE_CNT;
140     }
141     return err;
142 }
143 
144 // Reset efuse write registers
esp_efuse_utility_reset(void)145 void esp_efuse_utility_reset(void)
146 {
147     esp_efuse_utility_clear_program_registers();
148     for (int num_block = EFUSE_BLK0; num_block < EFUSE_BLK_MAX; num_block++) {
149         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) {
150             REG_WRITE(addr_wr_block, 0);
151         }
152     }
153 }
154 
155 // Erase the virt_blocks array.
esp_efuse_utility_erase_virt_blocks(void)156 void esp_efuse_utility_erase_virt_blocks(void)
157 {
158 #ifdef CONFIG_EFUSE_VIRTUAL
159     memset(virt_blocks, 0, sizeof(virt_blocks));
160 #endif
161 }
162 
163 // Fills the virt_blocks array by values from efuse_Rdata.
esp_efuse_utility_update_virt_blocks(void)164 void esp_efuse_utility_update_virt_blocks(void)
165 {
166 #ifdef CONFIG_EFUSE_VIRTUAL
167     ESP_EARLY_LOGI(TAG, "Loading virtual efuse blocks from real efuses");
168     for (int num_block = EFUSE_BLK0; num_block < EFUSE_BLK_MAX; num_block++) {
169         int subblock = 0;
170         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) {
171             virt_blocks[num_block][subblock++] = REG_READ(addr_rd_block);
172         }
173         ESP_EARLY_LOGD(TAG, "virt_blocks[%d] is filled by EFUSE_BLOCK%d", num_block, num_block);
174     }
175 #else
176     ESP_EARLY_LOGI(TAG, "Emulate efuse is disabled");
177 #endif
178 }
179 
180 // Prints efuse values for all registers.
181 #ifndef BOOTLOADER_BUILD
esp_efuse_utility_debug_dump_blocks(void)182 void esp_efuse_utility_debug_dump_blocks(void)
183 {
184     printf("EFUSE_BLKx:\n");
185 #ifdef CONFIG_EFUSE_VIRTUAL
186     for (int num_block = EFUSE_BLK0; num_block < EFUSE_BLK_MAX; num_block++) {
187         int num_reg = 0;
188         printf("%d) ", num_block);
189         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, num_reg++) {
190             printf("0x%08x ", virt_blocks[num_block][num_reg]);
191         }
192         printf("\n");
193     }
194 #else
195     for (int num_block = EFUSE_BLK0; num_block < EFUSE_BLK_MAX; num_block++) {
196         printf("%d) ", num_block);
197         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) {
198             printf("0x%08x ", REG_READ(addr_rd_block));
199         }
200         printf("\n");
201     }
202 #endif
203     printf("\n");
204 }
205 #endif // BOOTLOADER_BUILD
206 
207 // returns the number of array elements for placing these bits in an array with the length of each element equal to size_of_base.
esp_efuse_utility_get_number_of_items(int bits,int size_of_base)208 int esp_efuse_utility_get_number_of_items(int bits, int size_of_base)
209 {
210     return  bits / size_of_base + (bits % size_of_base > 0 ? 1 : 0);
211 }
212 
213 // Writing efuse register with checking of repeated programming of programmed bits.
esp_efuse_utility_write_reg(esp_efuse_block_t efuse_block,unsigned int num_reg,uint32_t reg_to_write)214 esp_err_t esp_efuse_utility_write_reg(esp_efuse_block_t efuse_block, unsigned int num_reg, uint32_t reg_to_write)
215 {
216     esp_err_t err = ESP_OK;
217     uint32_t reg = esp_efuse_utility_read_reg(efuse_block, num_reg);
218     if (reg & reg_to_write) {
219         ESP_EARLY_LOGE(TAG, "Repeated programming of programmed bits is strictly forbidden 0x%08x", reg & reg_to_write);
220         err = ESP_ERR_EFUSE_REPEATED_PROG;
221     } else {
222         write_reg(efuse_block, num_reg, reg_to_write);
223     }
224     return err;
225 }
226 
227 // Reading efuse register.
esp_efuse_utility_read_reg(esp_efuse_block_t blk,unsigned int num_reg)228 uint32_t esp_efuse_utility_read_reg(esp_efuse_block_t blk, unsigned int num_reg)
229 {
230     assert(blk >= 0 && blk < EFUSE_BLK_MAX);
231     unsigned int max_num_reg = (range_read_addr_blocks[blk].end - range_read_addr_blocks[blk].start) / sizeof(uint32_t);
232     assert(num_reg <= max_num_reg);
233     uint32_t value;
234 #ifdef CONFIG_EFUSE_VIRTUAL
235     value = virt_blocks[blk][num_reg];
236 #else
237     value = REG_READ(range_read_addr_blocks[blk].start + num_reg * 4);
238 #endif
239     return value;
240 }
241 
242 // Private functions
243 
244 // writing efuse register.
write_reg(esp_efuse_block_t blk,unsigned int num_reg,uint32_t value)245 static void write_reg(esp_efuse_block_t blk, unsigned int num_reg, uint32_t value)
246 {
247     assert(blk >= 0 && blk < EFUSE_BLK_MAX);
248     unsigned int max_num_reg = (range_read_addr_blocks[blk].end - range_read_addr_blocks[blk].start) / sizeof(uint32_t);
249     assert(num_reg <= max_num_reg);
250     uint32_t addr_wr_reg = range_write_addr_blocks[blk].start + num_reg * 4;
251     uint32_t reg_to_write = REG_READ(addr_wr_reg) | value;
252     // The register can be written in parts so we combine the new value with the one already available.
253     REG_WRITE(addr_wr_reg, reg_to_write);
254 }
255 
256 // return mask with required the number of ones with shift.
get_mask(unsigned int bit_count,unsigned int shift)257 static uint32_t get_mask(unsigned int bit_count, unsigned int shift)
258 {
259     uint32_t mask;
260     if (bit_count != 32) {
261         mask = (1 << bit_count) - 1;
262     } else {
263         mask = 0xFFFFFFFF;
264     }
265     return mask << shift;
266 }
267 
268 // return the register number in the array. return -1 if all registers for field was selected.
get_reg_num(int bit_start,int bit_count,int i_reg)269 static int get_reg_num(int bit_start, int bit_count, int i_reg)
270 {
271     int num_reg = i_reg + bit_start / 32;
272 
273     if (num_reg > (bit_start + bit_count - 1) / 32) {
274         return -1;
275     }
276 
277     return num_reg;
278 }
279 
280 // returns the starting bit number in the register.
get_starting_bit_num_in_reg(int bit_start,int i_reg)281 static int get_starting_bit_num_in_reg(int bit_start, int i_reg)
282 {
283     return (i_reg == 0) ? bit_start % 32 : 0;
284 }
285 
286 // Returns the number of bits in the register.
get_count_bits_in_reg(int bit_start,int bit_count,int i_reg)287 static int get_count_bits_in_reg(int bit_start, int bit_count, int i_reg)
288 {
289     int ret_count = 0;
290     int num_reg = 0;
291     int last_used_bit = (bit_start + bit_count - 1);
292     for (int num_bit = bit_start; num_bit <= last_used_bit; ++num_bit) {
293         ++ret_count;
294         if ((((num_bit + 1) % 32) == 0) || (num_bit == last_used_bit)) {
295             if (i_reg == num_reg++) {
296                 return ret_count;
297             }
298             ret_count = 0;
299         }
300     }
301     return 0;
302 }
303 
304 // fill efuse register from array.
fill_reg(int bit_start_in_reg,int bit_count_in_reg,uint8_t * blob,int * filled_bits_blob)305 static uint32_t fill_reg(int bit_start_in_reg, int bit_count_in_reg, uint8_t* blob, int* filled_bits_blob)
306 {
307     uint32_t reg_to_write = 0;
308     uint32_t temp_blob_32;
309     int shift_bit = (*filled_bits_blob) % 8;
310     if (shift_bit != 0) {
311         temp_blob_32 = blob[(*filled_bits_blob) / 8] >> shift_bit;
312         shift_bit = ((8 - shift_bit) < bit_count_in_reg) ? (8 - shift_bit) : bit_count_in_reg;
313         reg_to_write = temp_blob_32 & get_mask(shift_bit, 0);
314         (*filled_bits_blob) += shift_bit;
315         bit_count_in_reg -= shift_bit;
316     }
317 
318     int shift_reg = shift_bit;
319     while (bit_count_in_reg > 0) {
320         temp_blob_32 = blob[(*filled_bits_blob) / 8];
321         shift_bit = (bit_count_in_reg > 8) ? 8 : bit_count_in_reg;
322         reg_to_write |= (temp_blob_32 & get_mask(shift_bit, 0)) << shift_reg;
323         (*filled_bits_blob) += shift_bit;
324         bit_count_in_reg -= shift_bit;
325         shift_reg += 8;
326     };
327     return reg_to_write << bit_start_in_reg;
328 }
329 
330 // sets a required count of bits as "1".
set_cnt_in_reg(int bit_start_in_reg,int bit_count_used_in_reg,uint32_t reg_masked,size_t * cnt)331 static uint32_t set_cnt_in_reg(int bit_start_in_reg, int bit_count_used_in_reg, uint32_t reg_masked, size_t* cnt)
332 {
333     assert((bit_start_in_reg + bit_count_used_in_reg) <= 32);
334     uint32_t reg_to_write = 0;
335     for (int i = bit_start_in_reg; i < bit_start_in_reg + bit_count_used_in_reg; ++i) {
336         if ((reg_masked & (1 << i)) == 0) {
337             reg_to_write |= (1 << i);
338             if (--(*cnt) == 0) {
339                 break;
340             }
341         }
342     }
343     return reg_to_write;
344 }
345 
346 // check range of bits for any coding scheme.
check_range_of_bits(esp_efuse_block_t blk,int offset_in_bits,int size_bits)347 static bool check_range_of_bits(esp_efuse_block_t blk, int offset_in_bits, int size_bits)
348 {
349     int max_num_bit = offset_in_bits + size_bits;
350     if (max_num_bit > 256) {
351         return false;
352     } else {
353         ESP_EFUSE_FIELD_CORRESPONDS_CODING_SCHEME(blk, max_num_bit);
354     }
355     return true;
356 }
357