feat(espefuse): Adds incompatible eFuse settings check for S3

This commit is contained in:
Konstantin Kondrashov
2024-06-13 20:09:55 +03:00
committed by Radim Karniš
parent 1059ec7faf
commit c2448436fc
6 changed files with 83 additions and 0 deletions

View File

@@ -10,6 +10,10 @@ Positional arguments:
- ``eFuse name``
- ``value``
Optional arguments:
* ``--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.
It can be list of eFuse names and values (like EFUSE_NAME1 1 EFUSE_NAME2 7 EFUSE_NAME3 10 etc.).
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.

View File

@@ -649,6 +649,10 @@ class EspEfusesBase(object):
"""Returns (error count, failure boolean flag)"""
return self.blocks[block_num].num_errors, self.blocks[block_num].fail
def is_efuses_incompatible_for_burn(self):
# Overwrite this function for a specific target if you want to check if a certain eFuse(s) can be burned.
return False
class EfuseFieldBase(EfuseProtectBase):
def __init__(self, parent, param):

View File

@@ -74,6 +74,11 @@ def add_common_commands(subparsers, efuses):
+ [name for e in efuses.efuses for name in e.alt_names if name != ""],
efuses=efuses,
)
burn.add_argument(
"--force",
help="Suppress an error to burn eFuses",
action="store_true",
)
read_protect_efuse = subparsers.add_parser(
"read_protect_efuse",
@@ -480,6 +485,14 @@ def burn_efuse(esp, efuses, args):
)
print(" espefuse/esptool will not work.")
if efuses.is_efuses_incompatible_for_burn():
if args.force:
print("Ignore incompatible eFuse settings.")
else:
raise esptool.FatalError(
"Incompatible eFuse settings detected, abort. (use --force flag to skip it)."
)
if not efuses.burn_all(check_batch_mode=True):
return

View File

@@ -296,6 +296,28 @@ class EspEfuses(base_fields.EspEfusesBase):
output = "Flash voltage (VDD_SPI) set to 3.3V by efuse."
return output
def is_efuses_incompatible_for_burn(self):
# getting chip version: self._esp.get_chip_revision()
if (
(
self["DIS_USB_JTAG"].get()
and self["DIS_USB_SERIAL_JTAG"].get(from_read=False)
)
or (
self["DIS_USB_JTAG"].get(from_read=False)
and self["DIS_USB_SERIAL_JTAG"].get()
)
or (
self["DIS_USB_JTAG"].get(from_read=False)
and self["DIS_USB_SERIAL_JTAG"].get(from_read=False)
)
):
print(
"DIS_USB_JTAG and DIS_USB_SERIAL_JTAG cannot be set together due to a bug in the ROM bootloader!"
)
return True
return False
class EfuseField(base_fields.EfuseFieldBase):
@staticmethod

View File

@@ -296,6 +296,28 @@ class EspEfuses(base_fields.EspEfusesBase):
output = "Flash voltage (VDD_SPI) set to 3.3V by efuse."
return output
def is_efuses_incompatible_for_burn(self):
# getting chip version: self._esp.get_chip_revision()
if (
(
self["DIS_USB_JTAG"].get(from_read=True)
and self["DIS_USB_SERIAL_JTAG"].get(from_read=False)
)
or (
self["DIS_USB_JTAG"].get(from_read=False)
and self["DIS_USB_SERIAL_JTAG"].get(from_read=True)
)
or (
self["DIS_USB_JTAG"].get(from_read=False)
and self["DIS_USB_SERIAL_JTAG"].get(from_read=False)
)
):
print(
"DIS_USB_JTAG and DIS_USB_SERIAL_JTAG cannot be set together due to a bug in the ROM bootloader"
)
return True
return False
class EfuseField(base_fields.EfuseFieldBase):
@staticmethod

View File

@@ -801,6 +801,24 @@ class TestBurnEfuseCommands(EfuseTestCase):
ADC2_TP_HIGH 45"
)
@pytest.mark.skipif(
arg_chip != "esp32s3",
reason="Currently S3 only has this efuse incompatibility check",
)
def test_burn_efuse_incompatibility_check(self):
self.espefuse_py(
"burn_efuse DIS_USB_JTAG 1 DIS_USB_SERIAL_JTAG 1",
check_msg="Incompatible eFuse settings detected, abort",
ret_code=2,
)
self.espefuse_py("burn_efuse DIS_USB_JTAG 1")
self.espefuse_py(
"burn_efuse DIS_USB_SERIAL_JTAG 1",
check_msg="Incompatible eFuse settings detected, abort",
ret_code=2,
)
self.espefuse_py("burn_efuse DIS_USB_SERIAL_JTAG 1 --force")
class TestBurnKeyCommands(EfuseTestCase):
@pytest.mark.skipif(arg_chip != "esp32", reason="ESP32-only")