Skip to content

Commit c244843

Browse files
KonstantinKondrashovradimkarnis
authored andcommitted
feat(espefuse): Adds incompatible eFuse settings check for S3
1 parent 1059ec7 commit c244843

File tree

6 files changed

+83
-0
lines changed

6 files changed

+83
-0
lines changed

docs/en/espefuse/burn-efuse-cmd.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ Positional arguments:
1010
- ``eFuse name``
1111
- ``value``
1212

13+
Optional arguments:
14+
15+
* ``--force``. Suppress an error to burn eFuses. The tool checks for incompatible eFuse states to prevent them from burning and potentially **bricking the chip**. Use this flag only if you are sure. This will suppress the eFuse incompatibility error.
16+
1317
It can be list of eFuse names and values (like EFUSE_NAME1 1 EFUSE_NAME2 7 EFUSE_NAME3 10 etc.).
1418

1519
New values can be a numeric value in decimal or hex (with "0x" prefix). eFuse bits can only be burned from 0 to 1, attempting to set any back to 0 will have no effect. Most eFuses have a limited bit width (many are only 1-bit flags). Longer eFuses (MAC addresses, keys) can be set with this command, but it's better to use a specific command (``burn_custom_mac``, ``burn_key``) for a specific field.

espefuse/efuse/base_fields.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,10 @@ def get_block_errors(self, block_num):
649649
"""Returns (error count, failure boolean flag)"""
650650
return self.blocks[block_num].num_errors, self.blocks[block_num].fail
651651

652+
def is_efuses_incompatible_for_burn(self):
653+
# Overwrite this function for a specific target if you want to check if a certain eFuse(s) can be burned.
654+
return False
655+
652656

653657
class EfuseFieldBase(EfuseProtectBase):
654658
def __init__(self, parent, param):

espefuse/efuse/base_operations.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,11 @@ def check_efuse_name(efuse_name, efuse_list):
7474
+ [name for e in efuses.efuses for name in e.alt_names if name != ""],
7575
efuses=efuses,
7676
)
77+
burn.add_argument(
78+
"--force",
79+
help="Suppress an error to burn eFuses",
80+
action="store_true",
81+
)
7782

7883
read_protect_efuse = subparsers.add_parser(
7984
"read_protect_efuse",
@@ -480,6 +485,14 @@ def print_attention(blocked_efuses_after_burn):
480485
)
481486
print(" espefuse/esptool will not work.")
482487

488+
if efuses.is_efuses_incompatible_for_burn():
489+
if args.force:
490+
print("Ignore incompatible eFuse settings.")
491+
else:
492+
raise esptool.FatalError(
493+
"Incompatible eFuse settings detected, abort. (use --force flag to skip it)."
494+
)
495+
483496
if not efuses.burn_all(check_batch_mode=True):
484497
return
485498

espefuse/efuse/esp32s3/fields.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,28 @@ def summary(self):
296296
output = "Flash voltage (VDD_SPI) set to 3.3V by efuse."
297297
return output
298298

299+
def is_efuses_incompatible_for_burn(self):
300+
# getting chip version: self._esp.get_chip_revision()
301+
if (
302+
(
303+
self["DIS_USB_JTAG"].get()
304+
and self["DIS_USB_SERIAL_JTAG"].get(from_read=False)
305+
)
306+
or (
307+
self["DIS_USB_JTAG"].get(from_read=False)
308+
and self["DIS_USB_SERIAL_JTAG"].get()
309+
)
310+
or (
311+
self["DIS_USB_JTAG"].get(from_read=False)
312+
and self["DIS_USB_SERIAL_JTAG"].get(from_read=False)
313+
)
314+
):
315+
print(
316+
"DIS_USB_JTAG and DIS_USB_SERIAL_JTAG cannot be set together due to a bug in the ROM bootloader!"
317+
)
318+
return True
319+
return False
320+
299321

300322
class EfuseField(base_fields.EfuseFieldBase):
301323
@staticmethod

espefuse/efuse/esp32s3beta2/fields.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,28 @@ def summary(self):
296296
output = "Flash voltage (VDD_SPI) set to 3.3V by efuse."
297297
return output
298298

299+
def is_efuses_incompatible_for_burn(self):
300+
# getting chip version: self._esp.get_chip_revision()
301+
if (
302+
(
303+
self["DIS_USB_JTAG"].get(from_read=True)
304+
and self["DIS_USB_SERIAL_JTAG"].get(from_read=False)
305+
)
306+
or (
307+
self["DIS_USB_JTAG"].get(from_read=False)
308+
and self["DIS_USB_SERIAL_JTAG"].get(from_read=True)
309+
)
310+
or (
311+
self["DIS_USB_JTAG"].get(from_read=False)
312+
and self["DIS_USB_SERIAL_JTAG"].get(from_read=False)
313+
)
314+
):
315+
print(
316+
"DIS_USB_JTAG and DIS_USB_SERIAL_JTAG cannot be set together due to a bug in the ROM bootloader"
317+
)
318+
return True
319+
return False
320+
299321

300322
class EfuseField(base_fields.EfuseFieldBase):
301323
@staticmethod

test/test_espefuse.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -801,6 +801,24 @@ def test_burn_efuse_with_34_coding_scheme2(self):
801801
ADC2_TP_HIGH 45"
802802
)
803803

804+
@pytest.mark.skipif(
805+
arg_chip != "esp32s3",
806+
reason="Currently S3 only has this efuse incompatibility check",
807+
)
808+
def test_burn_efuse_incompatibility_check(self):
809+
self.espefuse_py(
810+
"burn_efuse DIS_USB_JTAG 1 DIS_USB_SERIAL_JTAG 1",
811+
check_msg="Incompatible eFuse settings detected, abort",
812+
ret_code=2,
813+
)
814+
self.espefuse_py("burn_efuse DIS_USB_JTAG 1")
815+
self.espefuse_py(
816+
"burn_efuse DIS_USB_SERIAL_JTAG 1",
817+
check_msg="Incompatible eFuse settings detected, abort",
818+
ret_code=2,
819+
)
820+
self.espefuse_py("burn_efuse DIS_USB_SERIAL_JTAG 1 --force")
821+
804822

805823
class TestBurnKeyCommands(EfuseTestCase):
806824
@pytest.mark.skipif(arg_chip != "esp32", reason="ESP32-only")

0 commit comments

Comments
 (0)