1 /**
2 ******************************************************************************
3 * @file bl616_ef_ctrl.c
4 * @version V1.0
5 * @date
6 * @brief This file is the standard driver c file
7 ******************************************************************************
8 * @attention
9 *
10 * <h2><center>© COPYRIGHT(c) 2020 Bouffalo Lab</center></h2>
11 *
12 * Redistribution and use in source and binary forms, with or without modification,
13 * are permitted provided that the following conditions are met:
14 * 1. Redistributions of source code must retain the above copyright notice,
15 * this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright notice,
17 * this list of conditions and the following disclaimer in the documentation
18 * and/or other materials provided with the distribution.
19 * 3. Neither the name of Bouffalo Lab nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 *
34 ******************************************************************************
35 */
36 #include "bl616_ef_cfg.h"
37 #include "hardware/ef_data_reg.h"
38
39 extern int bflb_efuse_read_mac_address_opt(uint8_t slot, uint8_t mac[6], uint8_t reload);
40
41 static const bflb_ef_ctrl_com_trim_cfg_t trim_list[] = {
42 {
43 .name = "ldo15",
44 .en_addr = 0x68 * 8 + 31,
45 .parity_addr = 0x68 * 8 + 30,
46 .value_addr = 0x68 * 8 + 27,
47 .value_len = 3,
48 },
49 {
50 .name = "iptat",
51 .en_addr = 0x74 * 8 + 31,
52 .parity_addr = 0x74 * 8 + 30,
53 .value_addr = 0x68 * 8 + 22,
54 .value_len = 5,
55 },
56 {
57 .name = "icx",
58 .en_addr = 0x74 * 8 + 29,
59 .parity_addr = 0x74 * 8 + 28,
60 .value_addr = 0x74 * 8 + 22,
61 .value_len = 6,
62 },
63 {
64 .name = "dcdc_trim",
65 .en_addr = 0x78 * 8 + 31,
66 .parity_addr = 0x78 * 8 + 30,
67 .value_addr = 0x78 * 8 + 26,
68 .value_len = 4,
69 },
70 {
71 .name = "ldo18_sel",
72 .en_addr = 0x78 * 8 + 25,
73 .parity_addr = 0x78 * 8 + 24,
74 .value_addr = 0x78 * 8 + 20,
75 .value_len = 4,
76 },
77 {
78 .name = "ldo18_trim",
79 .en_addr = 0x78 * 8 + 19,
80 .parity_addr = 0x78 * 8 + 18,
81 .value_addr = 0x78 * 8 + 14,
82 .value_len = 4,
83 },
84 {
85 .name = "ldo33_trim",
86 .en_addr = 0x78 * 8 + 13,
87 .parity_addr = 0x78 * 8 + 12,
88 .value_addr = 0x78 * 8 + 8,
89 .value_len = 4,
90 },
91 {
92 .name = "ldo11_tirm",
93 .en_addr = 0x78 * 8 + 7,
94 .parity_addr = 0x78 * 8 + 6,
95 .value_addr = 0x78 * 8 + 2,
96 .value_len = 4,
97 },
98 {
99 .name = "rc32m",
100 .en_addr = 0x78 * 8 + 1,
101 .parity_addr = 0x78 * 8 + 0,
102 .value_addr = 0x7C * 8 + 4,
103 .value_len = 8,
104 },
105 {
106 .name = "hp_poffset0",
107 .en_addr = 0xCC * 8 + 26,
108 .parity_addr = 0xC0 * 8 + 15,
109 .value_addr = 0xC0 * 8 + 0,
110 .value_len = 15,
111 },
112 {
113 .name = "hp_poffset1",
114 .en_addr = 0xCC * 8 + 27,
115 .parity_addr = 0xC0 * 8 + 31,
116 .value_addr = 0xC0 * 8 + 16,
117 .value_len = 15,
118 },
119 {
120 .name = "hp_poffset2",
121 .en_addr = 0xCC * 8 + 28,
122 .parity_addr = 0xC4 * 8 + 15,
123 .value_addr = 0xC4 * 8 + 0,
124 .value_len = 15,
125 },
126 {
127 .name = "lp_poffset0",
128 .en_addr = 0xCC * 8 + 29,
129 .parity_addr = 0xC4 * 8 + 31,
130 .value_addr = 0xC4 * 8 + 16,
131 .value_len = 15,
132 },
133 {
134 .name = "lp_poffset1",
135 .en_addr = 0xCC * 8 + 30,
136 .parity_addr = 0xC8 * 8 + 15,
137 .value_addr = 0xC8 * 8 + 0,
138 .value_len = 15,
139 },
140 {
141 .name = "lp_poffset2",
142 .en_addr = 0xCC * 8 + 31,
143 .parity_addr = 0xC8 * 8 + 31,
144 .value_addr = 0xC8 * 8 + 16,
145 .value_len = 15,
146 },
147 {
148 .name = "bz_poffset0",
149 .en_addr = 0xD0 * 8 + 26,
150 .parity_addr = 0xCC * 8 + 25,
151 .value_addr = 0xCC * 8 + 0,
152 .value_len = 25,
153 },
154 {
155 .name = "bz_poffset1",
156 .en_addr = 0xD0 * 8 + 27,
157 .parity_addr = 0xD0 * 8 + 25,
158 .value_addr = 0xD0 * 8 + 0,
159 .value_len = 25,
160 },
161 {
162 .name = "bz_poffset2",
163 .en_addr = 0xD0 * 8 + 28,
164 .parity_addr = 0xD4 * 8 + 25,
165 .value_addr = 0xD4 * 8 + 0,
166 .value_len = 25,
167 },
168 {
169 .name = "tmp_mp0",
170 .en_addr = 0xD8 * 8 + 9,
171 .parity_addr = 0xD8 * 8 + 8,
172 .value_addr = 0xD8 * 8 + 0,
173 .value_len = 8,
174 },
175 {
176 .name = "tmp_mp1",
177 .en_addr = 0xD8 * 8 + 19,
178 .parity_addr = 0xD8 * 8 + 18,
179 .value_addr = 0xD8 * 8 + 10,
180 .value_len = 8,
181 },
182 {
183 .name = "tmp_mp2",
184 .en_addr = 0xD8 * 8 + 29,
185 .parity_addr = 0xD8 * 8 + 28,
186 .value_addr = 0xD8 * 8 + 20,
187 .value_len = 8,
188 },
189 {
190 .name = "auadc_gain",
191 .en_addr = 0xDC * 8 + 25,
192 .parity_addr = 0xDC * 8 + 24,
193 .value_addr = 0xDC * 8 + 0,
194 .value_len = 24,
195 },
196 {
197 .name = "auadc_offset",
198 .en_addr = 0xE0 * 8 + 25,
199 .parity_addr = 0xE0 * 8 + 24,
200 .value_addr = 0xE0 * 8 + 0,
201 .value_len = 24,
202 },
203 {
204 .name = "psram_trim",
205 .en_addr = 0xE8 * 8 + 12,
206 .parity_addr = 0xE8 * 8 + 11,
207 .value_addr = 0xE8 * 8 + 0,
208 .value_len = 11,
209 },
210 {
211 .name = "rc32k",
212 .en_addr = 0xEC * 8 + 19,
213 .parity_addr = 0xEC * 8 + 18,
214 .value_addr = 0xEC * 8 + 8,
215 .value_len = 10,
216 },
217 {
218 .name = "xtal0",
219 .en_addr = 0xEC * 8 + 7,
220 .parity_addr = 0xEC * 8 + 6,
221 .value_addr = 0xEC * 8 + 0,
222 .value_len = 6,
223 },
224 {
225 .name = "xtal1",
226 .en_addr = 0xF0 * 8 + 31,
227 .parity_addr = 0xF0 * 8 + 30,
228 .value_addr = 0xF4 * 8 + 26,
229 .value_len = 6,
230 },
231 {
232 .name = "xtal2",
233 .en_addr = 0xF0 * 8 + 29,
234 .parity_addr = 0xF0 * 8 + 28,
235 .value_addr = 0xF4 * 8 + 20,
236 .value_len = 6,
237 },
238 {
239 .name = "gpadc_gain",
240 .en_addr = 0xF0 * 8 + 27,
241 .parity_addr = 0xF0 * 8 + 26,
242 .value_addr = 0xF0 * 8 + 14,
243 .value_len = 12,
244 },
245 {
246 .name = "tsen",
247 .en_addr = 0xF0 * 8 + 13,
248 .parity_addr = 0xF0 * 8 + 12,
249 .value_addr = 0xF0 * 8 + 0,
250 .value_len = 12,
251 },
252 {
253 .name = "dcdc_dis",
254 .en_addr = 0xF4 * 8 + 19,
255 .parity_addr = 0xF4 * 8 + 18,
256 .value_addr = 0xF4 * 8 + 17,
257 .value_len = 1,
258 },
259 {
260 .name = "dcdc_vout",
261 .en_addr = 0xF4 * 8 + 16,
262 .parity_addr = 0xF4 * 8 + 15,
263 .value_addr = 0xF4 * 8 + 10,
264 .value_len = 5,
265 },
266 {
267 .name = "ldo18_bypass",
268 .en_addr = 0xF4 * 8 + 9,
269 .parity_addr = 0xF4 * 8 + 8,
270 .value_addr = 0xF4 * 8 + 4,
271 .value_len = 1,
272 },
273 {
274 .name = "usb20",
275 .en_addr = 0xF8 * 8 + 15,
276 .parity_addr = 0xF8 * 8 + 14,
277 .value_addr = 0xF8 * 8 + 8,
278 .value_len = 6,
279 }
280 };
281
282 /****************************************************************************/ /**
283 * @brief Efuse get trim list
284 *
285 * @param trim_list: Trim list pointer
286 *
287 * @return Trim list count
288 *
289 *******************************************************************************/
bflb_ef_ctrl_get_common_trim_list(const bflb_ef_ctrl_com_trim_cfg_t ** ptrim_list)290 uint32_t bflb_ef_ctrl_get_common_trim_list(const bflb_ef_ctrl_com_trim_cfg_t **ptrim_list)
291 {
292 *ptrim_list = &trim_list[0];
293 return sizeof(trim_list) / sizeof(trim_list[0]);
294 }
295
296 /****************************************************************************/ /**
297 * @brief Efuse read device info
298 *
299 * @param deviceInfo: info pointer
300 *
301 * @return None
302 *
303 *******************************************************************************/
bflb_ef_ctrl_get_device_info(bflb_efuse_device_info_type * deviceInfo)304 void bflb_ef_ctrl_get_device_info(bflb_efuse_device_info_type *deviceInfo)
305 {
306 uint32_t *p = (uint32_t *)deviceInfo;
307
308 bflb_ef_ctrl_read_direct(NULL, EF_DATA_EF_WIFI_MAC_HIGH_OFFSET, p, 1, 1);
309 }
310
bflb_efuse_get_chipid(uint8_t chipid[8])311 void bflb_efuse_get_chipid(uint8_t chipid[8])
312 {
313 bflb_efuse_read_mac_address_opt(0, chipid, 1);
314 chipid[6] = 0;
315 chipid[7] = 0;
316 }
317
318 /****************************************************************************/ /**
319 * @brief Whether MAC address slot is empty
320 *
321 * @param slot: MAC address slot
322 * @param reload: whether reload to check
323 *
324 * @return 0 for all slots full,1 for others
325 *
326 *******************************************************************************/
bflb_efuse_is_mac_address_slot_empty(uint8_t slot,uint8_t reload)327 uint8_t bflb_efuse_is_mac_address_slot_empty(uint8_t slot, uint8_t reload)
328 {
329 uint32_t tmp1 = 0xffffffff, tmp2 = 0xffffffff;
330 uint32_t part1Empty = 0, part2Empty = 0;
331
332 if (slot == 0) {
333 bflb_ef_ctrl_read_direct(NULL, EF_DATA_EF_WIFI_MAC_LOW_OFFSET, &tmp1, 1, reload);
334 bflb_ef_ctrl_read_direct(NULL, EF_DATA_EF_WIFI_MAC_HIGH_OFFSET, &tmp2, 1, reload);
335 } else if (slot == 1) {
336 bflb_ef_ctrl_read_direct(NULL, EF_DATA_EF_SW_USAGE_2_OFFSET, &tmp1, 1, reload);
337 bflb_ef_ctrl_read_direct(NULL, EF_DATA_EF_SW_USAGE_3_OFFSET, &tmp2, 1, reload);
338 } else if (slot == 2) {
339 bflb_ef_ctrl_read_direct(NULL, EF_DATA_EF_KEY_SLOT_11_W1_OFFSET, &tmp1, 1, reload);
340 bflb_ef_ctrl_read_direct(NULL, EF_DATA_EF_KEY_SLOT_11_W2_OFFSET, &tmp2, 1, reload);
341 }
342
343 part1Empty = (bflb_ef_ctrl_is_all_bits_zero(tmp1, 0, 32));
344 part2Empty = (bflb_ef_ctrl_is_all_bits_zero(tmp2, 0, 22));
345
346 return (part1Empty && part2Empty);
347 }
348
349 /****************************************************************************/ /**
350 * @brief Efuse write optional MAC address
351 *
352 * @param slot: MAC address slot
353 * @param mac[6]: MAC address buffer
354 * @param program: Whether program
355 *
356 * @return 0 or -1
357 *
358 *******************************************************************************/
bflb_efuse_write_mac_address_opt(uint8_t slot,uint8_t mac[6],uint8_t program)359 int bflb_efuse_write_mac_address_opt(uint8_t slot, uint8_t mac[6], uint8_t program)
360 {
361 uint8_t *maclow = (uint8_t *)mac;
362 uint8_t *machigh = (uint8_t *)(mac + 4);
363 uint32_t tmpval;
364 uint32_t i = 0, cnt;
365
366 if (slot >= 3) {
367 return -1;
368 }
369
370 /* Change to local order */
371 for (i = 0; i < 3; i++) {
372 tmpval = mac[i];
373 mac[i] = mac[5 - i];
374 mac[5 - i] = tmpval;
375 }
376
377 /* The low 32 bits */
378 tmpval = BL_RDWD_FRM_BYTEP(maclow);
379
380 if (slot == 0) {
381 bflb_ef_ctrl_write_direct(NULL, EF_DATA_EF_WIFI_MAC_LOW_OFFSET, &tmpval, 1, program);
382 } else if (slot == 1) {
383 bflb_ef_ctrl_write_direct(NULL, EF_DATA_EF_SW_USAGE_2_OFFSET, &tmpval, 1, program);
384 } else if (slot == 2) {
385 bflb_ef_ctrl_write_direct(NULL, EF_DATA_EF_KEY_SLOT_11_W1_OFFSET, &tmpval, 1, program);
386 }
387
388 /* The high 16 bits */
389 tmpval = machigh[0] + (machigh[1] << 8);
390 cnt = 0;
391
392 for (i = 0; i < 6; i++) {
393 cnt += bflb_ef_ctrl_get_byte_zero_cnt(mac[i]);
394 }
395
396 tmpval |= ((cnt & 0x3f) << 16);
397
398 if (slot == 0) {
399 bflb_ef_ctrl_write_direct(NULL, EF_DATA_EF_WIFI_MAC_HIGH_OFFSET, &tmpval, 1, program);
400 } else if (slot == 1) {
401 bflb_ef_ctrl_write_direct(NULL, EF_DATA_EF_SW_USAGE_3_OFFSET, &tmpval, 1, program);
402 } else if (slot == 2) {
403 bflb_ef_ctrl_write_direct(NULL, EF_DATA_EF_KEY_SLOT_11_W2_OFFSET, &tmpval, 1, program);
404 }
405
406 return 0;
407 }
408
409 /****************************************************************************/ /**
410 * @brief Efuse read optional MAC address
411 *
412 * @param slot: MAC address slot
413 * @param mac[6]: MAC address buffer
414 * @param reload: Whether reload
415 *
416 * @return 0 or -1
417 *
418 *******************************************************************************/
bflb_efuse_read_mac_address_opt(uint8_t slot,uint8_t mac[6],uint8_t reload)419 int bflb_efuse_read_mac_address_opt(uint8_t slot, uint8_t mac[6], uint8_t reload)
420 {
421 uint8_t *maclow = (uint8_t *)mac;
422 uint8_t *machigh = (uint8_t *)(mac + 4);
423 uint32_t tmpval = 0;
424 uint32_t i = 0;
425 uint32_t cnt = 0;
426
427 if (slot >= 3) {
428 return -1;
429 }
430
431 if (slot == 0) {
432 bflb_ef_ctrl_read_direct(NULL, EF_DATA_EF_WIFI_MAC_LOW_OFFSET, &tmpval, 1, reload);
433 } else if (slot == 1) {
434 bflb_ef_ctrl_read_direct(NULL, EF_DATA_EF_SW_USAGE_2_OFFSET, &tmpval, 1, reload);
435 } else if (slot == 2) {
436 bflb_ef_ctrl_read_direct(NULL, EF_DATA_EF_KEY_SLOT_11_W1_OFFSET, &tmpval, 1, reload);
437 }
438
439 BL_WRWD_TO_BYTEP(maclow, tmpval);
440
441 if (slot == 0) {
442 bflb_ef_ctrl_read_direct(NULL, EF_DATA_EF_WIFI_MAC_HIGH_OFFSET, &tmpval, 1, reload);
443 } else if (slot == 1) {
444 bflb_ef_ctrl_read_direct(NULL, EF_DATA_EF_SW_USAGE_3_OFFSET, &tmpval, 1, reload);
445 } else if (slot == 2) {
446 bflb_ef_ctrl_read_direct(NULL, EF_DATA_EF_KEY_SLOT_11_W2_OFFSET, &tmpval, 1, reload);
447 }
448
449 machigh[0] = tmpval & 0xff;
450 machigh[1] = (tmpval >> 8) & 0xff;
451
452 /* Check parity */
453 for (i = 0; i < 6; i++) {
454 cnt += bflb_ef_ctrl_get_byte_zero_cnt(mac[i]);
455 }
456
457 if ((cnt & 0x3f) == ((tmpval >> 16) & 0x3f)) {
458 /* Change to network order */
459 for (i = 0; i < 3; i++) {
460 tmpval = mac[i];
461 mac[i] = mac[5 - i];
462 mac[5 - i] = tmpval;
463 }
464 return 0;
465 } else {
466 return -1;
467 }
468 }
469
bflb_efuse_get_adc_trim(void)470 float bflb_efuse_get_adc_trim(void)
471 {
472 bflb_ef_ctrl_com_trim_t trim;
473 uint32_t tmp;
474
475 float coe = 1.0;
476
477 bflb_ef_ctrl_read_common_trim(NULL, "gpadc_gain", &trim, 1);
478
479 if (trim.en) {
480 if (trim.parity == bflb_ef_ctrl_get_trim_parity(trim.value, trim.len)) {
481 tmp = trim.value;
482
483 if (tmp & 0x800) {
484 tmp = ~tmp;
485 tmp += 1;
486 tmp = tmp & 0xfff;
487 coe = (1.0 + ((float)tmp / 2048.0));
488 } else {
489 coe = (1.0 - ((float)tmp / 2048.0));
490 }
491 }
492 }
493
494 return coe;
495 }
496
bflb_efuse_get_adc_tsen_trim(void)497 uint32_t bflb_efuse_get_adc_tsen_trim(void)
498 {
499 bflb_ef_ctrl_com_trim_t trim;
500
501 bflb_ef_ctrl_read_common_trim(NULL, "tsen", &trim, 1);
502 if (trim.en) {
503 if (trim.parity == bflb_ef_ctrl_get_trim_parity(trim.value, trim.len)) {
504 return trim.value;
505 }
506 }
507
508 return 2042;
509 }
510
bflb_efuse_read_secure_boot(uint8_t * sign,uint8_t * aes)511 void bflb_efuse_read_secure_boot(uint8_t *sign, uint8_t *aes)
512 {
513 uint32_t tmpval = 0;
514
515 bflb_ef_ctrl_read_direct(NULL, EF_DATA_EF_CFG_0_OFFSET, &tmpval, 1, 1);
516 *sign = ((tmpval & EF_DATA_EF_SBOOT_SIGN_MODE_MSK) >> EF_DATA_EF_SBOOT_SIGN_MODE_POS) & 0x01;
517 *aes = ((tmpval & EF_DATA_EF_SF_AES_MODE_MSK) >> EF_DATA_EF_SF_AES_MODE_POS);
518 }
519
bflb_efuse_write_aes_key(uint8_t index,uint8_t * data,uint32_t len)520 void bflb_efuse_write_aes_key(uint8_t index, uint8_t *data, uint32_t len)
521 {
522 if ((index <= 3) || (index == 11)) {
523 index = ((index == 11) ? 5 : index);
524 /* Every key is 4 words len*/
525 bflb_ef_ctrl_write_direct(NULL, 0x1C + index * 4, (uint32_t *)data, len, 1);
526 } else if ((index < 11) && (index > 3)) {
527 index = index - 4;
528 /* Every key is 4 words len*/
529 bflb_ef_ctrl_write_direct(NULL, 0x80 + index * 4, (uint32_t *)data, len, 1);
530 }
531 }
532
bflb_efuse_read_aes_key(uint8_t index,uint8_t * data,uint32_t len)533 void bflb_efuse_read_aes_key(uint8_t index, uint8_t *data, uint32_t len)
534 {
535 if ((index <= 3) || (index == 11)) {
536 index = ((index == 11) ? 5 : index);
537 /* Every key is 4 words len*/
538 bflb_ef_ctrl_read_direct(NULL, 0x1C + index * 4, (uint32_t *)data, len, 1);
539 } else if ((index < 11) && (index > 3)) {
540 index = index - 4;
541 /* Every key is 4 words len*/
542 bflb_ef_ctrl_read_direct(NULL, 0x80 + index * 4, (uint32_t *)data, len, 1);
543 }
544 }
545
bflb_efuse_lock_aes_key_write(uint8_t index)546 void bflb_efuse_lock_aes_key_write(uint8_t index)
547 {
548 uint32_t lock = 0;
549
550 if ((index <= 3) || (index == 11)) {
551 index = ((index == 11) ? 8 : index);
552 lock |= (1 << (index + 17));
553 bflb_ef_ctrl_write_direct(NULL, 0x7c, &lock, 1, 1);
554 } else if ((index < 11) && (index > 3)) {
555 index = index - 4;
556 lock |= (1 << (index + 15));
557 bflb_ef_ctrl_write_direct(NULL, 0xfc, &lock, 1, 1);
558 }
559 }
560
bflb_efuse_lock_aes_key_read(uint8_t index)561 void bflb_efuse_lock_aes_key_read(uint8_t index)
562 {
563 uint32_t lock = 0;
564
565 if ((index <= 3) || (index == 11)) {
566 index = ((index == 11) ? 4 : index);
567 lock |= (1 << (index + 27));
568 bflb_ef_ctrl_write_direct(NULL, 0x7c, (uint32_t *)lock, 1, 1);
569 } else if ((index < 11) && (index > 3)) {
570 index = index - 4;
571 lock |= (1 << (index + 25));
572 bflb_ef_ctrl_write_direct(NULL, 0xfc, (uint32_t *)lock, 1, 1);
573 }
574 }
575
bflb_efuse_write_sw_usage(uint32_t index,uint32_t usage,uint8_t program)576 void bflb_efuse_write_sw_usage(uint32_t index, uint32_t usage, uint8_t program)
577 {
578 bflb_ef_ctrl_write_direct(NULL, EF_DATA_EF_SW_USAGE_0_OFFSET + index * 4, &usage, 1, program);
579 }
580
bflb_efuse_read_sw_usage(uint32_t index,uint32_t * usage)581 void bflb_efuse_read_sw_usage(uint32_t index, uint32_t *usage)
582 {
583 bflb_ef_ctrl_read_direct(NULL, EF_DATA_EF_SW_USAGE_0_OFFSET + index * 4, (uint32_t *)usage, 1, 1);
584 }