diff --git a/espefuse/__init__.py b/espefuse/__init__.py index 777d53f41..849c3a270 100755 --- a/espefuse/__init__.py +++ b/espefuse/__init__.py @@ -11,6 +11,7 @@ import espefuse.efuse.esp32 as esp32_efuse import espefuse.efuse.esp32c2 as esp32c2_efuse import espefuse.efuse.esp32c3 as esp32c3_efuse +import espefuse.efuse.esp32c5beta3 as esp32c5beta3_efuse import espefuse.efuse.esp32c6 as esp32c6_efuse import espefuse.efuse.esp32h2 as esp32h2_efuse import espefuse.efuse.esp32h2beta1 as esp32h2beta1_efuse @@ -49,6 +50,9 @@ "esp32c2": DefChip("ESP32-C2", esp32c2_efuse, esptool.targets.ESP32C2ROM), "esp32c3": DefChip("ESP32-C3", esp32c3_efuse, esptool.targets.ESP32C3ROM), "esp32c6": DefChip("ESP32-C6", esp32c6_efuse, esptool.targets.ESP32C6ROM), + "esp32c5beta3": DefChip( + "ESP32-C5(beta3)", esp32c5beta3_efuse, esptool.targets.ESP32C5BETA3ROM + ), "esp32h2": DefChip("ESP32-H2", esp32h2_efuse, esptool.targets.ESP32H2ROM), "esp32p4": DefChip("ESP32-P4", esp32p4_efuse, esptool.targets.ESP32P4ROM), "esp32h2beta1": DefChip( diff --git a/espefuse/efuse/esp32c5beta3/__init__.py b/espefuse/efuse/esp32c5beta3/__init__.py new file mode 100644 index 000000000..a3b55a802 --- /dev/null +++ b/espefuse/efuse/esp32c5beta3/__init__.py @@ -0,0 +1,3 @@ +from . import operations +from .emulate_efuse_controller import EmulateEfuseController +from .fields import EspEfuses diff --git a/espefuse/efuse/esp32c5beta3/emulate_efuse_controller.py b/espefuse/efuse/esp32c5beta3/emulate_efuse_controller.py new file mode 100644 index 000000000..27816831a --- /dev/null +++ b/espefuse/efuse/esp32c5beta3/emulate_efuse_controller.py @@ -0,0 +1,92 @@ +# This file describes eFuses controller for ESP32-C5 beta3 chip +# +# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD +# +# SPDX-License-Identifier: GPL-2.0-or-later + +import reedsolo + +from .mem_definition import EfuseDefineBlocks, EfuseDefineFields, EfuseDefineRegisters +from ..emulate_efuse_controller_base import EmulateEfuseControllerBase, FatalError + + +class EmulateEfuseController(EmulateEfuseControllerBase): + """The class for virtual efuse operation. Using for HOST_TEST.""" + + CHIP_NAME = "ESP32-C5(beta3)" + mem = None + debug = False + + def __init__(self, efuse_file=None, debug=False): + self.Blocks = EfuseDefineBlocks + self.Fields = EfuseDefineFields() + self.REGS = EfuseDefineRegisters + super(EmulateEfuseController, self).__init__(efuse_file, debug) + self.write_reg(self.REGS.EFUSE_CMD_REG, 0) + + """ esptool method start >>""" + + def get_major_chip_version(self): + return 0 + + def get_minor_chip_version(self): + return 0 + + def get_crystal_freq(self): + return 40 # MHz (common for all chips) + + def get_security_info(self): + return { + "flags": 0, + "flash_crypt_cnt": 0, + "key_purposes": 0, + "chip_id": 0, + "api_version": 0, + } + + """ << esptool method end """ + + def handle_writing_event(self, addr, value): + if addr == self.REGS.EFUSE_CMD_REG: + if value & self.REGS.EFUSE_PGM_CMD: + self.copy_blocks_wr_regs_to_rd_regs(updated_block=(value >> 2) & 0xF) + self.clean_blocks_wr_regs() + self.check_rd_protection_area() + self.write_reg(addr, 0) + self.write_reg(self.REGS.EFUSE_CMD_REG, 0) + elif value == self.REGS.EFUSE_READ_CMD: + self.write_reg(addr, 0) + self.write_reg(self.REGS.EFUSE_CMD_REG, 0) + self.save_to_file() + + def get_bitlen_of_block(self, blk, wr=False): + if blk.id == 0: + if wr: + return 32 * 8 + else: + return 32 * blk.len + else: + if wr: + rs_coding = 32 * 3 + return 32 * 8 + rs_coding + else: + return 32 * blk.len + + def handle_coding_scheme(self, blk, data): + if blk.id != 0: + # CODING_SCHEME RS applied only for all blocks except BLK0. + coded_bytes = 12 + data.pos = coded_bytes * 8 + plain_data = data.readlist("32*uint:8")[::-1] + # takes 32 bytes + # apply RS encoding + rs = reedsolo.RSCodec(coded_bytes) + # 32 byte of data + 12 bytes RS + calc_encoded_data = list(rs.encode([x for x in plain_data])) + data.pos = 0 + if calc_encoded_data != data.readlist("44*uint:8")[::-1]: + raise FatalError("Error in coding scheme data") + data = data[coded_bytes * 8 :] + if blk.len < 8: + data = data[(8 - blk.len) * 32 :] + return data diff --git a/espefuse/efuse/esp32c5beta3/fields.py b/espefuse/efuse/esp32c5beta3/fields.py new file mode 100644 index 000000000..416eb5807 --- /dev/null +++ b/espefuse/efuse/esp32c5beta3/fields.py @@ -0,0 +1,456 @@ +# This file describes eFuses for ESP32-C5 beta3 chip +# +# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD +# +# SPDX-License-Identifier: GPL-2.0-or-later + +import binascii +import struct +import sys +import time + +from bitstring import BitArray + +import esptool + +import reedsolo + +from .mem_definition import EfuseDefineBlocks, EfuseDefineFields, EfuseDefineRegisters +from .. import base_fields +from .. import util + + +class EfuseBlock(base_fields.EfuseBlockBase): + def len_of_burn_unit(self): + # The writing register window is 8 registers for any blocks. + # len in bytes + return 8 * 4 + + def __init__(self, parent, param, skip_read=False): + parent.read_coding_scheme() + super(EfuseBlock, self).__init__(parent, param, skip_read=skip_read) + + def apply_coding_scheme(self): + data = self.get_raw(from_read=False)[::-1] + if len(data) < self.len_of_burn_unit(): + add_empty_bytes = self.len_of_burn_unit() - len(data) + data = data + (b"\x00" * add_empty_bytes) + if self.get_coding_scheme() == self.parent.REGS.CODING_SCHEME_RS: + # takes 32 bytes + # apply RS encoding + rs = reedsolo.RSCodec(12) + # 32 byte of data + 12 bytes RS + encoded_data = rs.encode([x for x in data]) + words = struct.unpack("<" + "I" * 11, encoded_data) + # returns 11 words (8 words of data + 3 words of RS coding) + else: + # takes 32 bytes + words = struct.unpack("<" + ("I" * (len(data) // 4)), data) + # returns 8 words + return words + + +class EspEfuses(base_fields.EspEfusesBase): + """ + Wrapper object to manage the efuse fields in a connected ESP bootloader + """ + + debug = False + do_not_confirm = False + + def __init__(self, esp, skip_connect=False, debug=False, do_not_confirm=False): + self.Blocks = EfuseDefineBlocks() + self.Fields = EfuseDefineFields() + self.REGS = EfuseDefineRegisters + self.BURN_BLOCK_DATA_NAMES = self.Blocks.get_burn_block_data_names() + self.BLOCKS_FOR_KEYS = self.Blocks.get_blocks_for_keys() + self._esp = esp + self.debug = debug + self.do_not_confirm = do_not_confirm + if esp.CHIP_NAME != "ESP32-C5(beta3)": + raise esptool.FatalError( + "Expected the 'esp' param for ESP32-C5(beta3) chip but got for '%s'." + % (esp.CHIP_NAME) + ) + if not skip_connect: + flags = self._esp.get_security_info()["flags"] + GET_SECURITY_INFO_FLAG_SECURE_DOWNLOAD_ENABLE = 1 << 2 + if flags & GET_SECURITY_INFO_FLAG_SECURE_DOWNLOAD_ENABLE: + raise esptool.FatalError( + "Secure Download Mode is enabled. The tool can not read eFuses." + ) + self.blocks = [ + EfuseBlock(self, self.Blocks.get(block), skip_read=skip_connect) + for block in self.Blocks.BLOCKS + ] + if not skip_connect: + self.get_coding_scheme_warnings() + self.efuses = [EfuseField.convert(self, efuse) for efuse in self.Fields.EFUSES] + self.efuses += [ + EfuseField.convert(self, efuse) for efuse in self.Fields.KEYBLOCKS + ] + if skip_connect: + self.efuses += [ + EfuseField.convert(self, efuse) + for efuse in self.Fields.BLOCK2_CALIBRATION_EFUSES + ] + else: + if self["BLK_VERSION_MINOR"].get() == 1: + self.efuses += [ + EfuseField.convert(self, efuse) + for efuse in self.Fields.BLOCK2_CALIBRATION_EFUSES + ] + self.efuses += [ + EfuseField.convert(self, efuse) for efuse in self.Fields.CALC + ] + + def __getitem__(self, efuse_name): + """Return the efuse field with the given name""" + for e in self.efuses: + if efuse_name == e.name or any(x == efuse_name for x in e.alt_names): + return e + new_fields = False + for efuse in self.Fields.BLOCK2_CALIBRATION_EFUSES: + if efuse.name == efuse_name or any( + x == efuse_name for x in efuse.alt_names + ): + self.efuses += [ + EfuseField.convert(self, efuse) + for efuse in self.Fields.BLOCK2_CALIBRATION_EFUSES + ] + new_fields = True + if new_fields: + for e in self.efuses: + if efuse_name == e.name or any(x == efuse_name for x in e.alt_names): + return e + raise KeyError + + def read_coding_scheme(self): + self.coding_scheme = self.REGS.CODING_SCHEME_RS + + def print_status_regs(self): + print("") + self.blocks[0].print_block(self.blocks[0].err_bitarray, "err__regs", debug=True) + print( + "{:27} 0x{:08x}".format( + "EFUSE_RD_RS_ERR0_REG", self.read_reg(self.REGS.EFUSE_RD_RS_ERR0_REG) + ) + ) + print( + "{:27} 0x{:08x}".format( + "EFUSE_RD_RS_ERR1_REG", self.read_reg(self.REGS.EFUSE_RD_RS_ERR1_REG) + ) + ) + + def efuse_controller_setup(self): + self.set_efuse_timing() + self.clear_pgm_registers() + self.wait_efuse_idle() + + def write_efuses(self, block): + self.efuse_program(block) + return self.get_coding_scheme_warnings(silent=True) + + def clear_pgm_registers(self): + self.wait_efuse_idle() + for r in range( + self.REGS.EFUSE_PGM_DATA0_REG, self.REGS.EFUSE_PGM_DATA0_REG + 32, 4 + ): + self.write_reg(r, 0) + + def wait_efuse_idle(self): + deadline = time.time() + self.REGS.EFUSE_BURN_TIMEOUT + while time.time() < deadline: + cmds = self.REGS.EFUSE_PGM_CMD | self.REGS.EFUSE_READ_CMD + if self.read_reg(self.REGS.EFUSE_CMD_REG) & cmds == 0: + if self.read_reg(self.REGS.EFUSE_CMD_REG) & cmds == 0: + # Due to a hardware error, we have to read READ_CMD again + # to make sure the efuse clock is normal. + # For PGM_CMD it is not necessary. + return + raise esptool.FatalError( + "Timed out waiting for Efuse controller command to complete" + ) + + def efuse_program(self, block): + self.wait_efuse_idle() + self.write_reg(self.REGS.EFUSE_CONF_REG, self.REGS.EFUSE_WRITE_OP_CODE) + self.write_reg(self.REGS.EFUSE_CMD_REG, self.REGS.EFUSE_PGM_CMD | (block << 2)) + self.wait_efuse_idle() + self.clear_pgm_registers() + self.efuse_read() + + def efuse_read(self): + self.wait_efuse_idle() + self.write_reg(self.REGS.EFUSE_CONF_REG, self.REGS.EFUSE_READ_OP_CODE) + # need to add a delay after triggering EFUSE_READ_CMD, as ROM loader checks some + # efuse registers after each command is completed + # if ENABLE_SECURITY_DOWNLOAD or DIS_DOWNLOAD_MODE is enabled by the current cmd, then we need to try to reconnect to the chip. + try: + self.write_reg( + self.REGS.EFUSE_CMD_REG, self.REGS.EFUSE_READ_CMD, delay_after_us=1000 + ) + self.wait_efuse_idle() + except esptool.FatalError: + secure_download_mode_before = self._esp.secure_download_mode + + try: + self._esp = self.reconnect_chip(self._esp) + except esptool.FatalError: + print("Can not re-connect to the chip") + if not self["DIS_DOWNLOAD_MODE"].get() and self[ + "DIS_DOWNLOAD_MODE" + ].get(from_read=False): + print( + "This is the correct behavior as we are actually burning " + "DIS_DOWNLOAD_MODE which disables the connection to the chip" + ) + print("DIS_DOWNLOAD_MODE is enabled") + print("Successful") + sys.exit(0) # finish without errors + raise + + print("Established a connection with the chip") + if self._esp.secure_download_mode and not secure_download_mode_before: + print("Secure download mode is enabled") + if not self["ENABLE_SECURITY_DOWNLOAD"].get() and self[ + "ENABLE_SECURITY_DOWNLOAD" + ].get(from_read=False): + print( + "espefuse tool can not continue to work in Secure download mode" + ) + print("ENABLE_SECURITY_DOWNLOAD is enabled") + print("Successful") + sys.exit(0) # finish without errors + raise + + def set_efuse_timing(self): + """Set timing registers for burning efuses""" + # Configure clock + apb_freq = self.get_crystal_freq() + if apb_freq not in [40, 48]: + raise esptool.FatalError( + "The eFuse supports only xtal=40M and 48M (xtal was %d)" % apb_freq + ) + + self.update_reg(self.REGS.EFUSE_DAC_CONF_REG, self.REGS.EFUSE_DAC_NUM_M, 0xFF) + self.update_reg( + self.REGS.EFUSE_DAC_CONF_REG, self.REGS.EFUSE_DAC_CLK_DIV_M, 0x28 + ) + self.update_reg( + self.REGS.EFUSE_WR_TIM_CONF1_REG, self.REGS.EFUSE_PWR_ON_NUM_M, 0x3000 + ) + self.update_reg( + self.REGS.EFUSE_WR_TIM_CONF2_REG, self.REGS.EFUSE_PWR_OFF_NUM_M, 0x190 + ) + + def get_coding_scheme_warnings(self, silent=False): + """Check if the coding scheme has detected any errors.""" + old_addr_reg = 0 + reg_value = 0 + ret_fail = False + for block in self.blocks: + if block.id == 0: + words = [ + self.read_reg(self.REGS.EFUSE_RD_REPEAT_ERR0_REG + offs * 4) + for offs in range(5) + ] + block.err_bitarray.pos = 0 + for word in reversed(words): + block.err_bitarray.overwrite(BitArray("uint:32=%d" % word)) + block.num_errors = block.err_bitarray.count(True) + block.fail = block.num_errors != 0 + else: + addr_reg, err_num_mask, err_num_offs, fail_bit = self.REGS.BLOCK_ERRORS[ + block.id + ] + if err_num_mask is None or err_num_offs is None or fail_bit is None: + continue + if addr_reg != old_addr_reg: + old_addr_reg = addr_reg + reg_value = self.read_reg(addr_reg) + block.fail = reg_value & (1 << fail_bit) != 0 + block.num_errors = (reg_value >> err_num_offs) & err_num_mask + ret_fail |= block.fail + if not silent and (block.fail or block.num_errors): + print( + "Error(s) in BLOCK%d [ERRORS:%d FAIL:%d]" + % (block.id, block.num_errors, block.fail) + ) + if (self.debug or ret_fail) and not silent: + self.print_status_regs() + return ret_fail + + def summary(self): + # TODO add support set_flash_voltage - "Flash voltage (VDD_SPI)" + return "" + + +class EfuseField(base_fields.EfuseFieldBase): + @staticmethod + def convert(parent, efuse): + return { + "mac": EfuseMacField, + "keypurpose": EfuseKeyPurposeField, + "t_sensor": EfuseTempSensor, + "adc_tp": EfuseAdcPointCalibration, + "wafer": EfuseWafer, + }.get(efuse.class_type, EfuseField)(parent, efuse) + + +class EfuseWafer(EfuseField): + def get(self, from_read=True): + hi_bits = self.parent["WAFER_VERSION_MINOR_HI"].get(from_read) + assert self.parent["WAFER_VERSION_MINOR_HI"].bit_len == 1 + lo_bits = self.parent["WAFER_VERSION_MINOR_LO"].get(from_read) + assert self.parent["WAFER_VERSION_MINOR_LO"].bit_len == 3 + return (hi_bits << 3) + lo_bits + + def save(self, new_value): + raise esptool.FatalError("Burning %s is not supported" % self.name) + + +class EfuseTempSensor(EfuseField): + def get(self, from_read=True): + value = self.get_bitstring(from_read) + sig = -1 if value[0] else 1 + return sig * value[1:].uint * 0.1 + + +class EfuseAdcPointCalibration(EfuseField): + def get(self, from_read=True): + STEP_SIZE = 4 + value = self.get_bitstring(from_read) + sig = -1 if value[0] else 1 + return sig * value[1:].uint * STEP_SIZE + + +class EfuseMacField(EfuseField): + def check_format(self, new_value_str): + if new_value_str is None: + raise esptool.FatalError( + "Required MAC Address in AA:CD:EF:01:02:03 format!" + ) + num_bytes = 8 if self.name == "MAC_EUI64" else 6 + if new_value_str.count(":") != num_bytes - 1: + raise esptool.FatalError( + f"MAC Address needs to be a {num_bytes}-byte hexadecimal format " + "separated by colons (:)!" + ) + hexad = new_value_str.replace(":", "").split(" ", 1)[0] + hexad = hexad.split(" ", 1)[0] if self.is_field_calculated() else hexad + if len(hexad) != num_bytes * 2: + raise esptool.FatalError( + f"MAC Address needs to be a {num_bytes}-byte hexadecimal number " + f"({num_bytes * 2} hexadecimal characters)!" + ) + # order of bytearray = b'\xaa\xcd\xef\x01\x02\x03', + bindata = binascii.unhexlify(hexad) + + if not self.is_field_calculated(): + # unicast address check according to + # https://tools.ietf.org/html/rfc7042#section-2.1 + if esptool.util.byte(bindata, 0) & 0x01: + raise esptool.FatalError("Custom MAC must be a unicast MAC!") + return bindata + + def check(self): + errs, fail = self.parent.get_block_errors(self.block) + if errs != 0 or fail: + output = "Block%d has ERRORS:%d FAIL:%d" % (self.block, errs, fail) + else: + output = "OK" + return "(" + output + ")" + + def get(self, from_read=True): + if self.name == "CUSTOM_MAC": + mac = self.get_raw(from_read)[::-1] + elif self.name == "MAC": + mac = self.get_raw(from_read) + elif self.name == "MAC_EUI64": + mac = self.parent["MAC"].get_bitstring(from_read).copy() + mac_ext = self.parent["MAC_EXT"].get_bitstring(from_read) + mac.insert(mac_ext, 24) + mac = mac.bytes + else: + mac = self.get_raw(from_read) + return "%s %s" % (util.hexify(mac, ":"), self.check()) + + def save(self, new_value): + def print_field(e, new_value): + print( + " - '{}' ({}) {} -> {}".format( + e.name, e.description, e.get_bitstring(), new_value + ) + ) + + if self.name == "CUSTOM_MAC": + bitarray_mac = self.convert_to_bitstring(new_value) + print_field(self, bitarray_mac) + super(EfuseMacField, self).save(new_value) + else: + # Writing the BLOCK1 (MAC_SPI_8M_0) default MAC is not possible, + # as it's written in the factory. + raise esptool.FatalError(f"Burning {self.name} is not supported") + + +# fmt: off +class EfuseKeyPurposeField(EfuseField): + KEY_PURPOSES = [ + ("USER", 0, None, None, "no_need_rd_protect"), # User purposes (software-only use) + ("RESERVED", 1, None, None, "no_need_rd_protect"), # Reserved + ("XTS_AES_128_KEY", 4, None, "Reverse", "need_rd_protect"), # XTS_AES_128_KEY (flash/PSRAM encryption) + ("HMAC_DOWN_ALL", 5, None, None, "need_rd_protect"), # HMAC Downstream mode + ("HMAC_DOWN_JTAG", 6, None, None, "need_rd_protect"), # JTAG soft enable key (uses HMAC Downstream mode) + ("HMAC_DOWN_DIGITAL_SIGNATURE", 7, None, None, "need_rd_protect"), # Digital Signature peripheral key (uses HMAC Downstream mode) + ("HMAC_UP", 8, None, None, "need_rd_protect"), # HMAC Upstream mode + ("SECURE_BOOT_DIGEST0", 9, "DIGEST", None, "no_need_rd_protect"), # SECURE_BOOT_DIGEST0 (Secure Boot key digest) + ("SECURE_BOOT_DIGEST1", 10, "DIGEST", None, "no_need_rd_protect"), # SECURE_BOOT_DIGEST1 (Secure Boot key digest) + ("SECURE_BOOT_DIGEST2", 11, "DIGEST", None, "no_need_rd_protect"), # SECURE_BOOT_DIGEST2 (Secure Boot key digest) + ] +# fmt: on + KEY_PURPOSES_NAME = [name[0] for name in KEY_PURPOSES] + DIGEST_KEY_PURPOSES = [name[0] for name in KEY_PURPOSES if name[2] == "DIGEST"] + + def check_format(self, new_value_str): + # str convert to int: "XTS_AES_128_KEY" - > str(4) + # if int: 4 -> str(4) + raw_val = new_value_str + for purpose_name in self.KEY_PURPOSES: + if purpose_name[0] == new_value_str: + raw_val = str(purpose_name[1]) + break + if raw_val.isdigit(): + if int(raw_val) not in [p[1] for p in self.KEY_PURPOSES if p[1] > 0]: + raise esptool.FatalError("'%s' can not be set (value out of range)" % raw_val) + else: + raise esptool.FatalError("'%s' unknown name" % raw_val) + return raw_val + + def need_reverse(self, new_key_purpose): + for key in self.KEY_PURPOSES: + if key[0] == new_key_purpose: + return key[3] == "Reverse" + + def need_rd_protect(self, new_key_purpose): + for key in self.KEY_PURPOSES: + if key[0] == new_key_purpose: + return key[4] == "need_rd_protect" + + def get(self, from_read=True): + for p in self.KEY_PURPOSES: + if p[1] == self.get_raw(from_read): + return p[0] + return "FORBIDDEN_STATE" + + def get_name(self, raw_val): + for key in self.KEY_PURPOSES: + if key[1] == raw_val: + return key[0] + + def save(self, new_value): + raw_val = int(self.check_format(str(new_value))) + str_new_value = self.get_name(raw_val) + if self.name == "KEY_PURPOSE_5" and str_new_value.startswith("XTS_AES"): + raise esptool.FatalError(f"{self.name} can not have {str_new_value} key due to a hardware bug (please see TRM for more details)") + return super(EfuseKeyPurposeField, self).save(raw_val) diff --git a/espefuse/efuse/esp32c5beta3/mem_definition.py b/espefuse/efuse/esp32c5beta3/mem_definition.py new file mode 100644 index 000000000..f1b99495b --- /dev/null +++ b/espefuse/efuse/esp32c5beta3/mem_definition.py @@ -0,0 +1,169 @@ +# This file describes eFuses fields and registers for ESP32-C5 beta3 chip +# +# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD +# +# SPDX-License-Identifier: GPL-2.0-or-later + +import os + +import yaml + +from ..mem_definition_base import ( + EfuseBlocksBase, + EfuseFieldsBase, + EfuseRegistersBase, + Field, +) + + +class EfuseDefineRegisters(EfuseRegistersBase): + EFUSE_MEM_SIZE = 0x01FC + 4 + + # EFUSE registers & command/conf values + DR_REG_EFUSE_BASE = 0x600B0800 + EFUSE_PGM_DATA0_REG = DR_REG_EFUSE_BASE + EFUSE_CHECK_VALUE0_REG = DR_REG_EFUSE_BASE + 0x020 + EFUSE_CLK_REG = DR_REG_EFUSE_BASE + 0x1C8 + EFUSE_CONF_REG = DR_REG_EFUSE_BASE + 0x1CC + EFUSE_STATUS_REG = DR_REG_EFUSE_BASE + 0x1D0 + EFUSE_CMD_REG = DR_REG_EFUSE_BASE + 0x1D4 + EFUSE_RD_RS_ERR0_REG = DR_REG_EFUSE_BASE + 0x1C0 + EFUSE_RD_RS_ERR1_REG = DR_REG_EFUSE_BASE + 0x1C4 + EFUSE_RD_REPEAT_ERR0_REG = DR_REG_EFUSE_BASE + 0x17C + EFUSE_RD_REPEAT_ERR1_REG = DR_REG_EFUSE_BASE + 0x180 + EFUSE_RD_REPEAT_ERR2_REG = DR_REG_EFUSE_BASE + 0x184 + EFUSE_RD_REPEAT_ERR3_REG = DR_REG_EFUSE_BASE + 0x188 + EFUSE_RD_REPEAT_ERR4_REG = DR_REG_EFUSE_BASE + 0x18C + EFUSE_DAC_CONF_REG = DR_REG_EFUSE_BASE + 0x1E8 + EFUSE_RD_TIM_CONF_REG = DR_REG_EFUSE_BASE + 0x1EC + EFUSE_WR_TIM_CONF1_REG = DR_REG_EFUSE_BASE + 0x1F0 + EFUSE_WR_TIM_CONF2_REG = DR_REG_EFUSE_BASE + 0x1F4 + EFUSE_DATE_REG = DR_REG_EFUSE_BASE + 0x1FC + EFUSE_WRITE_OP_CODE = 0x5A5A + EFUSE_READ_OP_CODE = 0x5AA5 + EFUSE_PGM_CMD_MASK = 0x3 + EFUSE_PGM_CMD = 0x2 + EFUSE_READ_CMD = 0x1 + + BLOCK_ERRORS = [ + # error_reg, err_num_mask, err_num_offs, fail_bit + (EFUSE_RD_REPEAT_ERR0_REG, None, None, None), # BLOCK0 + (EFUSE_RD_RS_ERR0_REG, 0x7, 0, 3), # MAC_SPI_8M_0 + (EFUSE_RD_RS_ERR0_REG, 0x7, 4, 7), # BLOCK_SYS_DATA + (EFUSE_RD_RS_ERR0_REG, 0x7, 8, 11), # BLOCK_USR_DATA + (EFUSE_RD_RS_ERR0_REG, 0x7, 12, 15), # BLOCK_KEY0 + (EFUSE_RD_RS_ERR0_REG, 0x7, 16, 19), # BLOCK_KEY1 + (EFUSE_RD_RS_ERR0_REG, 0x7, 20, 23), # BLOCK_KEY2 + (EFUSE_RD_RS_ERR0_REG, 0x7, 24, 27), # BLOCK_KEY3 + (EFUSE_RD_RS_ERR0_REG, 0x7, 28, 31), # BLOCK_KEY4 + (EFUSE_RD_RS_ERR1_REG, 0x7, 0, 3), # BLOCK_KEY5 + (EFUSE_RD_RS_ERR1_REG, 0x7, 4, 7), # BLOCK_SYS_DATA2 + ] + + # EFUSE_WR_TIM_CONF2_REG + EFUSE_PWR_OFF_NUM_S = 0 + EFUSE_PWR_OFF_NUM_M = 0xFFFF << EFUSE_PWR_OFF_NUM_S + + # EFUSE_WR_TIM_CONF1_REG + EFUSE_PWR_ON_NUM_S = 8 + EFUSE_PWR_ON_NUM_M = 0x0000FFFF << EFUSE_PWR_ON_NUM_S + + # EFUSE_DAC_CONF_REG + EFUSE_DAC_CLK_DIV_S = 0 + EFUSE_DAC_CLK_DIV_M = 0xFF << EFUSE_DAC_CLK_DIV_S + + # EFUSE_DAC_CONF_REG + EFUSE_DAC_NUM_S = 9 + EFUSE_DAC_NUM_M = 0xFF << EFUSE_DAC_NUM_S + + +class EfuseDefineBlocks(EfuseBlocksBase): + __base_rd_regs = EfuseDefineRegisters.DR_REG_EFUSE_BASE + __base_wr_regs = EfuseDefineRegisters.EFUSE_PGM_DATA0_REG + # List of efuse blocks + # fmt: off + BLOCKS = [ + # Name, Alias, Index, Read address, Write address, Write protect bit, Read protect bit, Len, key_purpose + ("BLOCK0", [], 0, __base_rd_regs + 0x02C, __base_wr_regs, None, None, 6, None), + ("MAC_SPI_8M_0", ["BLOCK1"], 1, __base_rd_regs + 0x044, __base_wr_regs, 20, None, 6, None), + ("BLOCK_SYS_DATA", ["BLOCK2"], 2, __base_rd_regs + 0x05C, __base_wr_regs, 21, None, 8, None), + ("BLOCK_USR_DATA", ["BLOCK3"], 3, __base_rd_regs + 0x07C, __base_wr_regs, 22, None, 8, None), + ("BLOCK_KEY0", ["BLOCK4"], 4, __base_rd_regs + 0x09C, __base_wr_regs, 23, 0, 8, "KEY_PURPOSE_0"), + ("BLOCK_KEY1", ["BLOCK5"], 5, __base_rd_regs + 0x0BC, __base_wr_regs, 24, 1, 8, "KEY_PURPOSE_1"), + ("BLOCK_KEY2", ["BLOCK6"], 6, __base_rd_regs + 0x0DC, __base_wr_regs, 25, 2, 8, "KEY_PURPOSE_2"), + ("BLOCK_KEY3", ["BLOCK7"], 7, __base_rd_regs + 0x0FC, __base_wr_regs, 26, 3, 8, "KEY_PURPOSE_3"), + ("BLOCK_KEY4", ["BLOCK8"], 8, __base_rd_regs + 0x11C, __base_wr_regs, 27, 4, 8, "KEY_PURPOSE_4"), + ("BLOCK_KEY5", ["BLOCK9"], 9, __base_rd_regs + 0x13C, __base_wr_regs, 28, 5, 8, "KEY_PURPOSE_5"), + ("BLOCK_SYS_DATA2", ["BLOCK10"], 10, __base_rd_regs + 0x15C, __base_wr_regs, 29, 6, 8, None), + ] + # fmt: on + + def get_burn_block_data_names(self): + list_of_names = [] + for block in self.BLOCKS: + blk = self.get(block) + if blk.name: + list_of_names.append(blk.name) + if blk.alias: + for alias in blk.alias: + list_of_names.append(alias) + return list_of_names + + +class EfuseDefineFields(EfuseFieldsBase): + def __init__(self) -> None: + # List of efuse fields from TRM the chapter eFuse Controller. + self.EFUSES = [] + + self.KEYBLOCKS = [] + + # if BLK_VERSION_MINOR is 1, these efuse fields are in BLOCK2 + self.BLOCK2_CALIBRATION_EFUSES = [] + + self.CALC = [] + + dir_name = os.path.dirname(os.path.abspath(__file__)) + dir_name, file_name = os.path.split(dir_name) + file_name = file_name + ".yaml" + dir_name, _ = os.path.split(dir_name) + efuse_file = os.path.join(dir_name, "efuse_defs", file_name) + with open(f"{efuse_file}", "r") as r_file: + e_desc = yaml.safe_load(r_file) + super().__init__(e_desc) + + for i, efuse in enumerate(self.ALL_EFUSES): + if efuse.name in [ + "BLOCK_USR_DATA", + "BLOCK_KEY0", + "BLOCK_KEY1", + "BLOCK_KEY2", + "BLOCK_KEY3", + "BLOCK_KEY4", + "BLOCK_KEY5", + "BLOCK_SYS_DATA2", + ]: + if efuse.name == "BLOCK_USR_DATA": + efuse.bit_len = 256 + efuse.type = "bytes:32" + self.KEYBLOCKS.append(efuse) + self.ALL_EFUSES[i] = None + + elif efuse.category == "calibration": + self.BLOCK2_CALIBRATION_EFUSES.append(efuse) + self.ALL_EFUSES[i] = None + + f = Field() + f.name = "MAC_EUI64" + f.block = 1 + f.bit_len = 64 + f.type = f"bytes:{f.bit_len // 8}" + f.category = "MAC" + f.class_type = "mac" + f.description = "calc MAC_EUI64 = MAC[0]:MAC[1]:MAC[2]:MAC_EXT[0]:MAC_EXT[1]:MAC[3]:MAC[4]:MAC[5]" + self.CALC.append(f) + + for efuse in self.ALL_EFUSES: + if efuse is not None: + self.EFUSES.append(efuse) + + self.ALL_EFUSES = [] diff --git a/espefuse/efuse/esp32c5beta3/operations.py b/espefuse/efuse/esp32c5beta3/operations.py new file mode 100644 index 000000000..ed97563a7 --- /dev/null +++ b/espefuse/efuse/esp32c5beta3/operations.py @@ -0,0 +1,413 @@ +# This file includes the operations with eFuses for ESP32-C5 beta3 chip +# +# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD +# +# SPDX-License-Identifier: GPL-2.0-or-later + +import argparse +import os # noqa: F401. It is used in IDF scripts +import traceback + +import espsecure + +import esptool + +from . import fields +from .. import util +from ..base_operations import ( + add_common_commands, + add_force_write_always, + add_show_sensitive_info_option, + burn_bit, + burn_block_data, + burn_efuse, + check_error, + dump, + read_protect_efuse, + summary, + write_protect_efuse, +) + + +def protect_options(p): + p.add_argument( + "--no-write-protect", + help="Disable write-protecting of the key. The key remains writable. " + "(The keys use the RS coding scheme that does not support " + "post-write data changes. Forced write can damage RS encoding bits.) " + "The write-protecting of keypurposes does not depend on the option, " + "it will be set anyway.", + action="store_true", + ) + p.add_argument( + "--no-read-protect", + help="Disable read-protecting of the key. The key remains readable software." + "The key with keypurpose[USER, RESERVED and *_DIGEST] " + "will remain readable anyway. For the rest keypurposes the read-protection " + "will be defined the option (Read-protect by default).", + action="store_true", + ) + + +def add_commands(subparsers, efuses): + add_common_commands(subparsers, efuses) + burn_key = subparsers.add_parser( + "burn_key", help="Burn the key block with the specified name" + ) + protect_options(burn_key) + add_force_write_always(burn_key) + add_show_sensitive_info_option(burn_key) + burn_key.add_argument( + "block", + help="Key block to burn", + action="append", + choices=efuses.BLOCKS_FOR_KEYS, + ) + burn_key.add_argument( + "keyfile", + help="File containing 256 bits of binary key data", + action="append", + type=argparse.FileType("rb"), + ) + burn_key.add_argument( + "keypurpose", + help="Purpose to set.", + action="append", + choices=fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME, + ) + for _ in efuses.BLOCKS_FOR_KEYS: + burn_key.add_argument( + "block", + help="Key block to burn", + nargs="?", + action="append", + metavar="BLOCK", + choices=efuses.BLOCKS_FOR_KEYS, + ) + burn_key.add_argument( + "keyfile", + help="File containing 256 bits of binary key data", + nargs="?", + action="append", + metavar="KEYFILE", + type=argparse.FileType("rb"), + ) + burn_key.add_argument( + "keypurpose", + help="Purpose to set.", + nargs="?", + action="append", + metavar="KEYPURPOSE", + choices=fields.EfuseKeyPurposeField.KEY_PURPOSES_NAME, + ) + + burn_key_digest = subparsers.add_parser( + "burn_key_digest", + help="Parse a RSA public key and burn the digest to key efuse block", + ) + protect_options(burn_key_digest) + add_force_write_always(burn_key_digest) + add_show_sensitive_info_option(burn_key_digest) + burn_key_digest.add_argument( + "block", + help="Key block to burn", + action="append", + choices=efuses.BLOCKS_FOR_KEYS, + ) + burn_key_digest.add_argument( + "keyfile", + help="Key file to digest (PEM format)", + action="append", + type=argparse.FileType("rb"), + ) + burn_key_digest.add_argument( + "keypurpose", + help="Purpose to set.", + action="append", + choices=fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES, + ) + for _ in efuses.BLOCKS_FOR_KEYS: + burn_key_digest.add_argument( + "block", + help="Key block to burn", + nargs="?", + action="append", + metavar="BLOCK", + choices=efuses.BLOCKS_FOR_KEYS, + ) + burn_key_digest.add_argument( + "keyfile", + help="Key file to digest (PEM format)", + nargs="?", + action="append", + metavar="KEYFILE", + type=argparse.FileType("rb"), + ) + burn_key_digest.add_argument( + "keypurpose", + help="Purpose to set.", + nargs="?", + action="append", + metavar="KEYPURPOSE", + choices=fields.EfuseKeyPurposeField.DIGEST_KEY_PURPOSES, + ) + + p = subparsers.add_parser( + "set_flash_voltage", + help="Permanently set the internal flash voltage regulator " + "to either 1.8V, 3.3V or OFF. " + "This means GPIO45 can be high or low at reset without " + "changing the flash voltage.", + ) + p.add_argument("voltage", help="Voltage selection", choices=["1.8V", "3.3V", "OFF"]) + + p = subparsers.add_parser( + "burn_custom_mac", help="Burn a 48-bit Custom MAC Address to EFUSE BLOCK3." + ) + p.add_argument( + "mac", + help="Custom MAC Address to burn given in hexadecimal format with bytes " + "separated by colons (e.g. AA:CD:EF:01:02:03).", + type=fields.base_fields.CheckArgValue(efuses, "CUSTOM_MAC"), + ) + add_force_write_always(p) + + p = subparsers.add_parser("get_custom_mac", help="Prints the Custom MAC Address.") + + +def burn_custom_mac(esp, efuses, args): + efuses["CUSTOM_MAC"].save(args.mac) + if not efuses.burn_all(check_batch_mode=True): + return + get_custom_mac(esp, efuses, args) + print("Successful") + + +def get_custom_mac(esp, efuses, args): + print("Custom MAC Address: {}".format(efuses["CUSTOM_MAC"].get())) + + +def set_flash_voltage(esp, efuses, args): + raise esptool.FatalError("set_flash_voltage is not supported!") + + +def adc_info(esp, efuses, args): + print("") + # fmt: off + if efuses["BLK_VERSION_MINOR"].get() == 1: + print("Temperature Sensor Calibration = {}C".format(efuses["TEMP_CALIB"].get())) + + print("") + print("ADC1 Calibration data stored in efuse BLOCK2:") + print(f"OCODE: {efuses['OCODE'].get()}") + print(f"INIT_CODE_ATTEN0: {efuses['ADC1_INIT_CODE_ATTEN0'].get()}") + print(f"INIT_CODE_ATTEN1: {efuses['ADC1_INIT_CODE_ATTEN1'].get()}") + print(f"INIT_CODE_ATTEN2: {efuses['ADC1_INIT_CODE_ATTEN2'].get()}") + print(f"INIT_CODE_ATTEN3: {efuses['ADC1_INIT_CODE_ATTEN3'].get()}") + print(f"CAL_VOL_ATTEN0: {efuses['ADC1_CAL_VOL_ATTEN0'].get()}") + print(f"CAL_VOL_ATTEN1: {efuses['ADC1_CAL_VOL_ATTEN1'].get()}") + print(f"CAL_VOL_ATTEN2: {efuses['ADC1_CAL_VOL_ATTEN2'].get()}") + print(f"CAL_VOL_ATTEN3: {efuses['ADC1_CAL_VOL_ATTEN3'].get()}") + print(f"INIT_CODE_ATTEN0_CH0: {efuses['ADC1_INIT_CODE_ATTEN0_CH0'].get()}") + print(f"INIT_CODE_ATTEN0_CH1: {efuses['ADC1_INIT_CODE_ATTEN0_CH1'].get()}") + print(f"INIT_CODE_ATTEN0_CH2: {efuses['ADC1_INIT_CODE_ATTEN0_CH2'].get()}") + print(f"INIT_CODE_ATTEN0_CH3: {efuses['ADC1_INIT_CODE_ATTEN0_CH3'].get()}") + print(f"INIT_CODE_ATTEN0_CH4: {efuses['ADC1_INIT_CODE_ATTEN0_CH4'].get()}") + print(f"INIT_CODE_ATTEN0_CH5: {efuses['ADC1_INIT_CODE_ATTEN0_CH5'].get()}") + print(f"INIT_CODE_ATTEN0_CH6: {efuses['ADC1_INIT_CODE_ATTEN0_CH6'].get()}") + else: + print("BLK_VERSION_MINOR = {}".format(efuses["BLK_VERSION_MINOR"].get_meaning())) + # fmt: on + + +def burn_key(esp, efuses, args, digest=None): + if digest is None: + datafile_list = args.keyfile[ + 0 : len([name for name in args.keyfile if name is not None]) : + ] + else: + datafile_list = digest[0 : len([name for name in digest if name is not None]) :] + efuses.force_write_always = args.force_write_always + block_name_list = args.block[ + 0 : len([name for name in args.block if name is not None]) : + ] + keypurpose_list = args.keypurpose[ + 0 : len([name for name in args.keypurpose if name is not None]) : + ] + + util.check_duplicate_name_in_list(block_name_list) + if len(block_name_list) != len(datafile_list) or len(block_name_list) != len( + keypurpose_list + ): + raise esptool.FatalError( + "The number of blocks (%d), datafile (%d) and keypurpose (%d) " + "should be the same." + % (len(block_name_list), len(datafile_list), len(keypurpose_list)) + ) + + print("Burn keys to blocks:") + for block_name, datafile, keypurpose in zip( + block_name_list, datafile_list, keypurpose_list + ): + efuse = None + for block in efuses.blocks: + if block_name == block.name or block_name in block.alias: + efuse = efuses[block.name] + if efuse is None: + raise esptool.FatalError("Unknown block name - %s" % (block_name)) + num_bytes = efuse.bit_len // 8 + + block_num = efuses.get_index_block_by_name(block_name) + block = efuses.blocks[block_num] + + if digest is None: + data = datafile.read() + else: + data = datafile + + print(" - %s" % (efuse.name), end=" ") + revers_msg = None + if efuses[block.key_purpose_name].need_reverse(keypurpose): + revers_msg = "\tReversing byte order for AES-XTS hardware peripheral" + data = data[::-1] + print( + "-> [{}]".format( + util.hexify(data, " ") + if args.show_sensitive_info + else " ".join(["??"] * len(data)) + ) + ) + if revers_msg: + print(revers_msg) + if len(data) != num_bytes: + raise esptool.FatalError( + "Incorrect key file size %d. Key file must be %d bytes (%d bits) " + "of raw binary key data." % (len(data), num_bytes, num_bytes * 8) + ) + + if efuses[block.key_purpose_name].need_rd_protect(keypurpose): + read_protect = False if args.no_read_protect else True + else: + read_protect = False + write_protect = not args.no_write_protect + + # using efuse instead of a block gives the advantage of checking it as the whole field. + efuse.save(data) + + disable_wr_protect_key_purpose = False + if efuses[block.key_purpose_name].get() != keypurpose: + if efuses[block.key_purpose_name].is_writeable(): + print( + "\t'%s': '%s' -> '%s'." + % ( + block.key_purpose_name, + efuses[block.key_purpose_name].get(), + keypurpose, + ) + ) + efuses[block.key_purpose_name].save(keypurpose) + disable_wr_protect_key_purpose = True + else: + raise esptool.FatalError( + "It is not possible to change '%s' to '%s' " + "because write protection bit is set." + % (block.key_purpose_name, keypurpose) + ) + else: + print("\t'%s' is already '%s'." % (block.key_purpose_name, keypurpose)) + if efuses[block.key_purpose_name].is_writeable(): + disable_wr_protect_key_purpose = True + + if disable_wr_protect_key_purpose: + print("\tDisabling write to '%s'." % block.key_purpose_name) + efuses[block.key_purpose_name].disable_write() + + if read_protect: + print("\tDisabling read to key block") + efuse.disable_read() + + if write_protect: + print("\tDisabling write to key block") + efuse.disable_write() + print("") + + if not write_protect: + print("Keys will remain writeable (due to --no-write-protect)") + if args.no_read_protect: + print("Keys will remain readable (due to --no-read-protect)") + + if not efuses.burn_all(check_batch_mode=True): + return + print("Successful") + + +def burn_key_digest(esp, efuses, args): + digest_list = [] + datafile_list = args.keyfile[ + 0 : len([name for name in args.keyfile if name is not None]) : + ] + block_list = args.block[ + 0 : len([block for block in args.block if block is not None]) : + ] + for block_name, datafile in zip(block_list, datafile_list): + efuse = None + for block in efuses.blocks: + if block_name == block.name or block_name in block.alias: + efuse = efuses[block.name] + if efuse is None: + raise esptool.FatalError("Unknown block name - %s" % (block_name)) + num_bytes = efuse.bit_len // 8 + digest = espsecure._digest_sbv2_public_key(datafile) + if len(digest) != num_bytes: + raise esptool.FatalError( + "Incorrect digest size %d. Digest must be %d bytes (%d bits) " + "of raw binary key data." % (len(digest), num_bytes, num_bytes * 8) + ) + digest_list.append(digest) + burn_key(esp, efuses, args, digest=digest_list) + + +def espefuse(esp, efuses, args, command): + parser = argparse.ArgumentParser() + subparsers = parser.add_subparsers(dest="operation") + add_commands(subparsers, efuses) + try: + cmd_line_args = parser.parse_args(command.split()) + except SystemExit: + traceback.print_stack() + raise esptool.FatalError('"{}" - incorrect command'.format(command)) + if cmd_line_args.operation == "execute_scripts": + configfiles = cmd_line_args.configfiles + index = cmd_line_args.index + # copy arguments from args to cmd_line_args + vars(cmd_line_args).update(vars(args)) + if cmd_line_args.operation == "execute_scripts": + cmd_line_args.configfiles = configfiles + cmd_line_args.index = index + if cmd_line_args.operation is None: + parser.print_help() + parser.exit(1) + operation_func = globals()[cmd_line_args.operation] + # each 'operation' is a module-level function of the same name + operation_func(esp, efuses, cmd_line_args) + + +def execute_scripts(esp, efuses, args): + efuses.batch_mode_cnt += 1 + del args.operation + scripts = args.scripts + del args.scripts + + for file in scripts: + with open(file.name, "r") as file: + exec(compile(file.read(), file.name, "exec")) + + if args.debug: + for block in efuses.blocks: + data = block.get_bitstring(from_read=False) + block.print_block(data, "regs_for_burn", args.debug) + + efuses.batch_mode_cnt -= 1 + if not efuses.burn_all(check_batch_mode=True): + return + print("Successful") diff --git a/espsecure/__init__.py b/espsecure/__init__.py index 3e5ef2039..b4b50d632 100755 --- a/espsecure/__init__.py +++ b/espsecure/__init__.py @@ -1712,7 +1712,7 @@ def main(custom_commandline=None): "--aes_xts", "-x", help="Decrypt data using AES-XTS as used on " - "ESP32-S2, ESP32-C2, ESP32-C3, ESP32-C6 and ESP32-P4", + "ESP32-S2, ESP32-C2, ESP32-C3, ESP32-C6, ESP32-C5 and ESP32-P4", action="store_true", ) p.add_argument( @@ -1752,7 +1752,7 @@ def main(custom_commandline=None): "--aes_xts", "-x", help="Encrypt data using AES-XTS as used on " - "ESP32-S2, ESP32-C2, ESP32-C3, ESP32-C6 and ESP32-P4", + "ESP32-S2, ESP32-C2, ESP32-C3, ESP32-C6, ESP32-C5 and ESP32-P4", action="store_true", ) p.add_argument( diff --git a/esptool/bin_image.py b/esptool/bin_image.py index 55ca6359e..4e917316d 100644 --- a/esptool/bin_image.py +++ b/esptool/bin_image.py @@ -19,6 +19,7 @@ from .targets import ( ESP32C2ROM, ESP32C3ROM, + ESP32C5BETA3ROM, ESP32C6BETAROM, ESP32C6ROM, ESP32H2BETA1ROM, @@ -82,6 +83,7 @@ def select_image_class(f, chip): "esp32h2beta2": ESP32H2BETA2FirmwareImage, "esp32c2": ESP32C2FirmwareImage, "esp32c6": ESP32C6FirmwareImage, + "esp32c5beta3": ESP32C5BETA3FirmwareImage, "esp32h2": ESP32H2FirmwareImage, "esp32p4": ESP32P4FirmwareImage, }[chip](f) @@ -1114,6 +1116,15 @@ def set_mmu_page_size(self, size): ESP32C6ROM.BOOTLOADER_IMAGE = ESP32C6FirmwareImage +class ESP32C5BETA3FirmwareImage(ESP32C6FirmwareImage): + """ESP32C5BETA3 Firmware Image almost exactly the same as ESP32C6FirmwareImage""" + + ROM_LOADER = ESP32C5BETA3ROM + + +ESP32C5BETA3ROM.BOOTLOADER_IMAGE = ESP32C5BETA3FirmwareImage + + class ESP32P4FirmwareImage(ESP32FirmwareImage): """ESP32P4 Firmware Image almost exactly the same as ESP32FirmwareImage""" diff --git a/esptool/loader.py b/esptool/loader.py index bc08a919f..802531f2d 100644 --- a/esptool/loader.py +++ b/esptool/loader.py @@ -1454,7 +1454,12 @@ def get_crystal_freq(self): # See the self.XTAL_CLK_DIVIDER parameter for this factor. uart_div = self.read_reg(self.UART_CLKDIV_REG) & self.UART_CLKDIV_MASK est_xtal = (self._port.baudrate * uart_div) / 1e6 / self.XTAL_CLK_DIVIDER - norm_xtal = 40 if est_xtal > 33 else 26 + if est_xtal > 45: + norm_xtal = 48 + elif est_xtal > 33: + norm_xtal = 40 + else: + norm_xtal = 26 if abs(norm_xtal - est_xtal) > 1: print( "WARNING: Detected crystal freq %.2fMHz is quite different to " diff --git a/esptool/targets/__init__.py b/esptool/targets/__init__.py index dd1ba485d..16e204ed4 100644 --- a/esptool/targets/__init__.py +++ b/esptool/targets/__init__.py @@ -1,6 +1,7 @@ from .esp32 import ESP32ROM from .esp32c2 import ESP32C2ROM from .esp32c3 import ESP32C3ROM +from .esp32c5beta3 import ESP32C5BETA3ROM from .esp32c6 import ESP32C6ROM from .esp32c6beta import ESP32C6BETAROM from .esp32h2 import ESP32H2ROM @@ -25,6 +26,7 @@ "esp32h2beta2": ESP32H2BETA2ROM, "esp32c2": ESP32C2ROM, "esp32c6": ESP32C6ROM, + "esp32c5beta3": ESP32C5BETA3ROM, "esp32h2": ESP32H2ROM, "esp32p4": ESP32P4ROM, } diff --git a/esptool/targets/esp32c5beta3.py b/esptool/targets/esp32c5beta3.py new file mode 100644 index 000000000..0eeedc710 --- /dev/null +++ b/esptool/targets/esp32c5beta3.py @@ -0,0 +1,99 @@ +# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD +# +# SPDX-License-Identifier: GPL-2.0-or-later + +import struct +import time + +from .esp32c6 import ESP32C6ROM +from ..loader import ESPLoader + + +class ESP32C5BETA3ROM(ESP32C6ROM): + CHIP_NAME = "ESP32-C5(beta3)" + IMAGE_CHIP_ID = 17 + + IROM_MAP_START = 0x41000000 + IROM_MAP_END = 0x41800000 + DROM_MAP_START = 0x41000000 + DROM_MAP_END = 0x41800000 + + # Magic value for ESP32C5(beta3) + CHIP_DETECT_MAGIC_VALUE = [0xE10D8082] + + FLASH_FREQUENCY = { + "80m": 0xF, + "40m": 0x0, + "20m": 0x2, + } + + MEMORY_MAP = [ + [0x00000000, 0x00010000, "PADDING"], + [0x41800000, 0x42000000, "DROM"], + [0x40800000, 0x40880000, "DRAM"], + [0x40800000, 0x40880000, "BYTE_ACCESSIBLE"], + [0x4004A000, 0x40050000, "DROM_MASK"], + [0x40000000, 0x4004A000, "IROM_MASK"], + [0x41000000, 0x41800000, "IROM"], + [0x40800000, 0x40880000, "IRAM"], + [0x50000000, 0x50004000, "RTC_IRAM"], + [0x50000000, 0x50004000, "RTC_DRAM"], + [0x600FE000, 0x60100000, "MEM_INTERNAL2"], + ] + + def get_chip_description(self): + chip_name = { + 0: "ESP32-C5 beta3 (QFN40)", + }.get(self.get_pkg_version(), "unknown ESP32-C5 beta3") + major_rev = self.get_major_chip_version() + minor_rev = self.get_minor_chip_version() + return f"{chip_name} (revision v{major_rev}.{minor_rev})" + + def get_crystal_freq(self): + # The crystal detection algorithm of ESP32/ESP8266 + # works for ESP32-C5 beta3 as well. + return ESPLoader.get_crystal_freq(self) + + def change_baud(self, baud): + rom_with_48M_XTAL = not self.IS_STUB and self.get_crystal_freq() == 48 + if rom_with_48M_XTAL: + # The code is copied over from ESPLoader.change_baud(). + # Probably this is just a temporary solution until the next chip revision. + + # The ROM code thinks it uses a 40 MHz XTAL. Recompute the baud rate + # in order to trick the ROM code to set the correct baud rate for + # a 48 MHz XTAL. + false_rom_baud = baud * 40 // 48 + + print(f"Changing baud rate to {baud}") + self.command( + self.ESP_CHANGE_BAUDRATE, struct.pack(" $@" $(Q) $(CROSS_ESPRISCV32)gcc $(CFLAGS_ESPRISCV32) -DESP32C6=1 -Tstub_32c6.ld -Wl,-Map=$(@:.elf=.map) -o $@ $(filter %.c, $^) $(LDLIBS) +$(STUB_ELF_32C5_BETA_3): $(SRCS) $(BUILD_DIR) ld/stub_32c5_beta_3.ld + @echo " CC(32C5BETA3) $^ -> $@" + $(Q) $(CROSS_ESPRISCV32)gcc $(CFLAGS_ESPRISCV32) -DESP32C5BETA3=1 -Tstub_32c5_beta_3.ld -Wl,-Map=$(@:.elf=.map) -o $@ $(filter %.c, $^) $(LDLIBS) + $(STUB_ELF_32H2): $(SRCS) $(BUILD_DIR) ld/stub_32h2.ld @echo " CC(32H2) $^ -> $@" $(Q) $(CROSS_ESPRISCV32)gcc $(CFLAGS_ESPRISCV32) -DESP32H2=1 -Tstub_32h2.ld -Wl,-Map=$(@:.elf=.map) -o $@ $(filter %.c, $^) $(LDLIBS) diff --git a/flasher_stub/include/rom_functions.h b/flasher_stub/include/rom_functions.h index 6259dae88..ca0237220 100644 --- a/flasher_stub/include/rom_functions.h +++ b/flasher_stub/include/rom_functions.h @@ -18,11 +18,11 @@ int uart_rx_one_char(uint8_t *ch); uint8_t uart_rx_one_char_block(); int uart_tx_one_char(char ch); -#if ESP32C6 || ESP32H2 +#if ESP32C6 || ESP32H2 || ESP32C5BETA3 /* uart_tx_one_char doesn't send data to USB device serial, needs to be replaced */ int uart_tx_one_char2(char ch); #define uart_tx_one_char(ch) uart_tx_one_char2(ch) -#endif // ESP32C6 || ESP32H2 +#endif // ESP32C6 || ESP32H2 || ESP32C5BETA3 void uart_div_modify(uint32_t uart_no, uint32_t baud_div); diff --git a/flasher_stub/include/soc_support.h b/flasher_stub/include/soc_support.h index f095adbb5..d77430765 100644 --- a/flasher_stub/include/soc_support.h +++ b/flasher_stub/include/soc_support.h @@ -46,6 +46,11 @@ #define WITH_USB_OTG 1 #endif // ESP32S3 +#ifdef ESP32C5BETA3 +#define WITH_USB_JTAG_SERIAL 1 +#define IS_RISCV 1 +#endif // ESP32C5BETA3 + #ifdef ESP32C6 #define WITH_USB_JTAG_SERIAL 1 #define IS_RISCV 1 @@ -167,7 +172,7 @@ #define DR_REG_IO_MUX_BASE 0x60009000 #endif -#ifdef ESP32C6 +#if ESP32C6 || ESP32C5BETA3 #define UART_BASE_REG 0x60000000 /* UART0 */ #define SPI_BASE_REG 0x60003000 /* SPI peripheral 1, used for SPI flash */ #define SPI0_BASE_REG 0x60002000 /* SPI peripheral 0, inner state machine */ @@ -325,14 +330,14 @@ #define ETS_USB_INUM 17 /* arbitrary level 1 level interrupt */ #endif // ESP32S3 -#ifdef ESP32C6 +#if ESP32C6 || ESP32C5BETA3 #define UART_USB_JTAG_SERIAL 3 #define DR_REG_INTERRUPT_MATRIX_BASE 0x60010000 #define INTERRUPT_CORE0_USB_INTR_MAP_REG (DR_REG_INTERRUPT_MATRIX_BASE + 0xC0) /* USB-JTAG-Serial, INTMTX_CORE0_USB_INTR_MAP_REG */ #define ETS_USB_INUM 17 /* arbitrary level 1 level interrupt */ -#endif // ESP32C6 +#endif // ESP32C6 || ESP32C5BETA3 #ifdef ESP32H2 #define UART_USB_JTAG_SERIAL 3 @@ -384,7 +389,7 @@ #define RTC_CNTL_SWD_AUTO_FEED_EN (1 << 31) #endif -#ifdef ESP32C6 +#if ESP32C6 || ESP32C5BETA3 #define RTC_CNTL_WDTCONFIG0_REG (DR_REG_LP_WDT_BASE + 0x0) // LP_WDT_RWDT_CONFIG0_REG #define RTC_CNTL_WDTWPROTECT_REG (DR_REG_LP_WDT_BASE + 0x0018) // LP_WDT_RWDT_WPROTECT_REG #define RTC_CNTL_SWD_CONF_REG (DR_REG_LP_WDT_BASE + 0x001C) // LP_WDT_SWD_CONFIG_REG @@ -437,6 +442,14 @@ #define SYSTEM_SOC_CLK_MAX 1 #endif // ESP32S2 +#ifdef ESP32C5BETA3 +#define PCR_SYSCLK_CONF_REG (DR_REG_PCR_BASE + 0x10c) +#define PCR_SOC_CLK_SEL_M ((PCR_SOC_CLK_SEL_V)<<(PCR_SOC_CLK_SEL_S)) +#define PCR_SOC_CLK_SEL_V 0x3 +#define PCR_SOC_CLK_SEL_S 16 +#define PCR_SOC_CLK_MAX 3 // CPU_CLK frequency is 240 MHz (source is PLL_F240_CLK) +#endif // ESP32C5BETA3 + #ifdef ESP32C6 #define PCR_SYSCLK_CONF_REG (DR_REG_PCR_BASE + 0x110) #define PCR_SOC_CLK_SEL_M ((PCR_SOC_CLK_SEL_V)<<(PCR_SOC_CLK_SEL_S)) @@ -474,7 +487,7 @@ #define ROM_SPIFLASH_LEGACY 0x3ffae270 #endif // ESP32 || ESP32S2 || ESP32S3 || ESP32S3BETA2 -#if ESP32C3 || ESP32C6BETA || ESP32C2 || ESP32C6 +#if ESP32C3 || ESP32C6BETA || ESP32C2 || ESP32C6 || ESP32C5BETA3 #define ROM_SPIFLASH_LEGACY 0x3fcdfff4 #endif // ESP32C3 || ESP32C6BETA || ESP32C2 || ESP32C6 @@ -540,7 +553,7 @@ #define FUNC_GPIO 1 #endif // ESP32C2 -#if ESP32C6 || ESP32C6BETA +#if ESP32C6 || ESP32C6BETA || ESP32C5BETA3 #define PERIPHS_IO_MUX_SPICLK_U (DR_REG_IO_MUX_BASE + 0x78) #define PERIPHS_IO_MUX_SPIQ_U (DR_REG_IO_MUX_BASE + 0x68) #define PERIPHS_IO_MUX_SPID_U (DR_REG_IO_MUX_BASE + 0x7c) diff --git a/flasher_stub/ld/rom_32c5_beta_3.ld b/flasher_stub/ld/rom_32c5_beta_3.ld new file mode 100755 index 000000000..d9c3d3e5e --- /dev/null +++ b/flasher_stub/ld/rom_32c5_beta_3.ld @@ -0,0 +1,429 @@ +/* ROM function interface esp32c5.rom.ld for esp32c5 + * + * + * Generated from ./target/esp32c5/interface-esp32c5.yml md5sum 2476337377df636dda217b0b3c1a63db + * + * Compatible with ROM where ECO version equal or greater to 0. + * + * THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT. + */ + +/*************************************** + Group common + ***************************************/ + +PROVIDE ( SPIWrite = esp_rom_spiflash_write); +PROVIDE ( SPI_read_status_high = esp_rom_spiflash_read_statushigh); +PROVIDE ( SPI_write_status = esp_rom_spiflash_write_status); +PROVIDE ( SPIRead = esp_rom_spiflash_read); +PROVIDE ( SPIParamCfg = esp_rom_spiflash_config_param); +PROVIDE ( SPIEraseChip = esp_rom_spiflash_erase_chip); +PROVIDE ( SPIEraseSector = esp_rom_spiflash_erase_sector); +PROVIDE ( SPIEraseBlock = esp_rom_spiflash_erase_block); +PROVIDE ( SPI_Write_Encrypt_Enable = esp_rom_spiflash_write_encrypted_enable); +PROVIDE ( SPI_Write_Encrypt_Disable = esp_rom_spiflash_write_encrypted_disable); +PROVIDE ( SPI_Encrypt_Write = esp_rom_spiflash_write_encrypted); + +/*************************************** + Group common + ***************************************/ + +/* Functions */ +rtc_get_reset_reason = 0x40000018; +rtc_get_wakeup_cause = 0x4000001c; +pmu_enable_unhold_pads = 0x40000020; +ets_printf = 0x40000024; +ets_install_putc1 = 0x40000028; +ets_install_putc2 = 0x4000002c; +ets_install_uart_printf = 0x40000030; +ets_install_usb_printf = 0x40000034; +ets_get_printf_channel = 0x40000038; +ets_delay_us = 0x4000003c; +ets_get_cpu_frequency = 0x40000040; +ets_update_cpu_frequency = 0x40000044; +ets_install_lock = 0x40000048; +UartRxString = 0x4000004c; +UartGetCmdLn = 0x40000050; +uart_tx_one_char = 0x40000054; +uart_tx_one_char2 = 0x40000058; +uart_tx_one_char3 = 0x4000005c; +uart_rx_one_char = 0x40000060; +uart_rx_one_char_block = 0x40000064; +uart_rx_intr_handler = 0x40000068; +uart_rx_readbuff = 0x4000006c; +uartAttach = 0x40000070; +uart_tx_flush = 0x40000074; +uart_tx_wait_idle = 0x40000078; +uart_div_modify = 0x4000007c; +ets_write_char_uart = 0x40000080; +uart_tx_switch = 0x40000084; +uart_buff_switch = 0x40000088; +roundup2 = 0x4000008c; +multofup = 0x40000090; +software_reset = 0x40000094; +software_reset_cpu = 0x40000098; +ets_clk_assist_debug_clock_enable = 0x4000009c; +clear_super_wdt_reset_flag = 0x400000a0; +disable_default_watchdog = 0x400000a4; +esp_rom_set_rtc_wake_addr = 0x400000a8; +esp_rom_get_rtc_wake_addr = 0x400000ac; +send_packet = 0x400000b0; +recv_packet = 0x400000b4; +GetUartDevice = 0x400000b8; +UartDwnLdProc = 0x400000bc; +GetSecurityInfoProc = 0x400000c0; +Uart_Init = 0x400000c4; +ets_set_user_start = 0x400000c8; +/* Data (.data, .bss, .rodata) */ +ets_rom_layout_p = 0x4004fffc; +ets_ops_table_ptr = 0x4087fff8; +g_saved_pc = 0x4087fffc; + + +/*************************************** + Group miniz + ***************************************/ + +/* Functions */ +mz_adler32 = 0x400000cc; +mz_free = 0x400000d0; +tdefl_compress = 0x400000d4; +tdefl_compress_buffer = 0x400000d8; +tdefl_compress_mem_to_heap = 0x400000dc; +tdefl_compress_mem_to_mem = 0x400000e0; +tdefl_compress_mem_to_output = 0x400000e4; +tdefl_get_adler32 = 0x400000e8; +tdefl_get_prev_return_status = 0x400000ec; +tdefl_init = 0x400000f0; +tdefl_write_image_to_png_file_in_memory = 0x400000f4; +tdefl_write_image_to_png_file_in_memory_ex = 0x400000f8; +tinfl_decompress = 0x400000fc; +tinfl_decompress_mem_to_callback = 0x40000100; +tinfl_decompress_mem_to_heap = 0x40000104; +tinfl_decompress_mem_to_mem = 0x40000108; + + +/*************************************** + Group spiflash_legacy + ***************************************/ + +/* Functions */ +esp_rom_spiflash_wait_idle = 0x4000010c; +esp_rom_spiflash_write_encrypted = 0x40000110; +esp_rom_spiflash_write_encrypted_dest = 0x40000114; +esp_rom_spiflash_write_encrypted_enable = 0x40000118; +esp_rom_spiflash_write_encrypted_disable = 0x4000011c; +esp_rom_spiflash_erase_chip = 0x40000120; +_esp_rom_spiflash_erase_sector = 0x40000124; +_esp_rom_spiflash_erase_block = 0x40000128; +_esp_rom_spiflash_write = 0x4000012c; +_esp_rom_spiflash_read = 0x40000130; +_esp_rom_spiflash_unlock = 0x40000134; +_SPIEraseArea = 0x40000138; +_SPI_write_enable = 0x4000013c; +esp_rom_spiflash_erase_sector = 0x40000140; +esp_rom_spiflash_erase_block = 0x40000144; +esp_rom_spiflash_write = 0x40000148; +esp_rom_spiflash_read = 0x4000014c; +esp_rom_spiflash_unlock = 0x40000150; +SPIEraseArea = 0x40000154; +SPI_write_enable = 0x40000158; +esp_rom_spiflash_config_param = 0x4000015c; +esp_rom_spiflash_read_user_cmd = 0x40000160; +esp_rom_spiflash_select_qio_pins = 0x40000164; +esp_rom_spi_flash_auto_sus_res = 0x40000168; +esp_rom_spi_flash_send_resume = 0x4000016c; +esp_rom_spi_flash_update_id = 0x40000170; +esp_rom_spiflash_config_clk = 0x40000174; +esp_rom_spiflash_config_readmode = 0x40000178; +esp_rom_spiflash_read_status = 0x4000017c; +esp_rom_spiflash_read_statushigh = 0x40000180; +esp_rom_spiflash_write_status = 0x40000184; +esp_rom_spiflash_write_disable = 0x40000188; +spi_cache_mode_switch = 0x4000018c; +spi_common_set_dummy_output = 0x40000190; +spi_common_set_flash_cs_timing = 0x40000194; +esp_rom_spi_set_address_bit_len = 0x40000198; +SPILock = 0x4000019c; +SPIMasterReadModeCnfig = 0x400001a0; +SPI_Common_Command = 0x400001a4; +SPI_WakeUp = 0x400001a8; +SPI_block_erase = 0x400001ac; +SPI_chip_erase = 0x400001b0; +SPI_init = 0x400001b4; +SPI_page_program = 0x400001b8; +SPI_read_data = 0x400001bc; +SPI_sector_erase = 0x400001c0; +SelectSpiFunction = 0x400001c4; +SetSpiDrvs = 0x400001c8; +Wait_SPI_Idle = 0x400001cc; +spi_dummy_len_fix = 0x400001d0; +Disable_QMode = 0x400001d4; +Enable_QMode = 0x400001d8; +spi_flash_attach = 0x400001dc; +spi_flash_get_chip_size = 0x400001e0; +spi_flash_guard_set = 0x400001e4; +spi_flash_guard_get = 0x400001e8; +spi_flash_read_encrypted = 0x400001ec; +/* Data (.data, .bss, .rodata) */ +rom_spiflash_legacy_funcs = 0x4087fff0; +rom_spiflash_legacy_data = 0x4087ffec; +g_flash_guard_ops = 0x4087fff4; + + +/*************************************** + Group hal_wdt + ***************************************/ + +/* Functions */ +wdt_hal_init = 0x40000390; +wdt_hal_deinit = 0x40000394; +wdt_hal_config_stage = 0x40000398; +wdt_hal_write_protect_disable = 0x4000039c; +wdt_hal_write_protect_enable = 0x400003a0; +wdt_hal_enable = 0x400003a4; +wdt_hal_disable = 0x400003a8; +wdt_hal_handle_intr = 0x400003ac; +wdt_hal_feed = 0x400003b0; +wdt_hal_set_flashboot_en = 0x400003b4; +wdt_hal_is_enabled = 0x400003b8; + + +/*************************************** + Group hal_systimer + ***************************************/ + +/* Functions */ +systimer_hal_init = 0x400003bc; +systimer_hal_deinit = 0x400003c0; +systimer_hal_set_tick_rate_ops = 0x400003c4; +systimer_hal_get_counter_value = 0x400003c8; +systimer_hal_get_time = 0x400003cc; +systimer_hal_set_alarm_target = 0x400003d0; +systimer_hal_set_alarm_period = 0x400003d4; +systimer_hal_get_alarm_value = 0x400003d8; +systimer_hal_enable_alarm_int = 0x400003dc; +systimer_hal_on_apb_freq_update = 0x400003e0; +systimer_hal_counter_value_advance = 0x400003e4; +systimer_hal_enable_counter = 0x400003e8; +systimer_hal_select_alarm_mode = 0x400003ec; +systimer_hal_connect_alarm_counter = 0x400003f0; +systimer_hal_counter_can_stall_by_cpu = 0x400003f4; + + +/*************************************** + Group cache + ***************************************/ + +/* Functions */ +Cache_Get_ICache_Line_Size = 0x40000624; +Cache_Get_Mode = 0x40000628; +Cache_Address_Through_Cache = 0x4000062c; +ROM_Boot_Cache_Init = 0x40000630; +MMU_Set_Page_Mode = 0x40000634; +MMU_Get_Page_Mode = 0x40000638; +Cache_Invalidate_ICache_Items = 0x4000063c; +Cache_Op_Addr = 0x40000640; +Cache_Invalidate_Addr = 0x40000644; +Cache_Invalidate_ICache_All = 0x40000648; +Cache_Mask_All = 0x4000064c; +Cache_UnMask_Dram0 = 0x40000650; +Cache_Suspend_ICache_Autoload = 0x40000654; +Cache_Resume_ICache_Autoload = 0x40000658; +Cache_Start_ICache_Preload = 0x4000065c; +Cache_ICache_Preload_Done = 0x40000660; +Cache_End_ICache_Preload = 0x40000664; +Cache_Config_ICache_Autoload = 0x40000668; +Cache_Enable_ICache_Autoload = 0x4000066c; +Cache_Disable_ICache_Autoload = 0x40000670; +Cache_Enable_ICache_PreLock = 0x40000674; +Cache_Disable_ICache_PreLock = 0x40000678; +Cache_Lock_ICache_Items = 0x4000067c; +Cache_Unlock_ICache_Items = 0x40000680; +Cache_Lock_Addr = 0x40000684; +Cache_Unlock_Addr = 0x40000688; +Cache_Disable_ICache = 0x4000068c; +Cache_Enable_ICache = 0x40000690; +Cache_Suspend_ICache = 0x40000694; +Cache_Resume_ICache = 0x40000698; +Cache_Freeze_ICache_Enable = 0x4000069c; +Cache_Freeze_ICache_Disable = 0x400006a0; +Cache_Set_IDROM_MMU_Size = 0x400006a4; +Cache_Get_IROM_MMU_End = 0x400006a8; +Cache_Get_DROM_MMU_End = 0x400006ac; +Cache_MMU_Init = 0x400006b0; +Cache_MSPI_MMU_Set = 0x400006b4; +Cache_MSPI_MMU_Set_Secure = 0x400006b8; +Cache_Travel_Tag_Memory = 0x400006bc; +Cache_Get_Virtual_Addr = 0x400006c0; +/* Data (.data, .bss, .rodata) */ +rom_cache_op_cb = 0x4087ffcc; +rom_cache_internal_table_ptr = 0x4087ffc8; + + +/*************************************** + Group clock + ***************************************/ + +/* Functions */ +ets_clk_get_xtal_freq = 0x400006c4; +ets_clk_get_cpu_freq = 0x400006c8; + + +/*************************************** + Group gpio + ***************************************/ + +/* Functions */ +gpio_set_output_level = 0x400006cc; +gpio_get_input_level = 0x400006d0; +gpio_matrix_in = 0x400006d4; +gpio_matrix_out = 0x400006d8; +gpio_bypass_matrix_in = 0x400006dc; +gpio_output_disable = 0x400006e0; +gpio_output_enable = 0x400006e4; +gpio_pad_input_disable = 0x400006e8; +gpio_pad_input_enable = 0x400006ec; +gpio_pad_pulldown = 0x400006f0; +gpio_pad_pullup = 0x400006f4; +gpio_pad_select_gpio = 0x400006f8; +gpio_pad_set_drv = 0x400006fc; +gpio_pad_unhold = 0x40000700; +gpio_pad_hold = 0x40000704; + + +/*************************************** + Group interrupts + ***************************************/ + +/* Functions */ +esprv_intc_int_set_priority = 0x40000708; +esprv_intc_int_set_threshold = 0x4000070c; +esprv_intc_int_enable = 0x40000710; +esprv_intc_int_disable = 0x40000714; +esprv_intc_int_set_type = 0x40000718; +PROVIDE( intr_handler_set = 0x4000071c ); +intr_matrix_set = 0x40000720; +ets_intr_lock = 0x40000724; +ets_intr_unlock = 0x40000728; +ets_isr_attach = 0x4000072c; +ets_isr_mask = 0x40000730; +ets_isr_unmask = 0x40000734; + + +/*************************************** + Group crypto + ***************************************/ + +/* Functions */ +md5_vector = 0x40000738; +MD5Init = 0x4000073c; +MD5Update = 0x40000740; +MD5Final = 0x40000744; +crc32_le = 0x40000748; +crc16_le = 0x4000074c; +crc8_le = 0x40000750; +crc32_be = 0x40000754; +crc16_be = 0x40000758; +crc8_be = 0x4000075c; +esp_crc8 = 0x40000760; +ets_sha_enable = 0x40000764; +ets_sha_disable = 0x40000768; +ets_sha_get_state = 0x4000076c; +ets_sha_init = 0x40000770; +ets_sha_process = 0x40000774; +ets_sha_starts = 0x40000778; +ets_sha_update = 0x4000077c; +ets_sha_finish = 0x40000780; +ets_sha_clone = 0x40000784; +ets_hmac_enable = 0x40000788; +ets_hmac_disable = 0x4000078c; +ets_hmac_calculate_message = 0x40000790; +ets_hmac_calculate_downstream = 0x40000794; +ets_hmac_invalidate_downstream = 0x40000798; +ets_jtag_enable_temporarily = 0x4000079c; +ets_aes_enable = 0x400007a0; +ets_aes_disable = 0x400007a4; +ets_aes_setkey = 0x400007a8; +ets_aes_block = 0x400007ac; +ets_aes_setkey_dec = 0x400007b0; +ets_aes_setkey_enc = 0x400007b4; +ets_bigint_enable = 0x400007b8; +ets_bigint_disable = 0x400007bc; +ets_bigint_multiply = 0x400007c0; +ets_bigint_modmult = 0x400007c4; +ets_bigint_modexp = 0x400007c8; +ets_bigint_wait_finish = 0x400007cc; +ets_bigint_getz = 0x400007d0; +ets_ds_enable = 0x400007d4; +ets_ds_disable = 0x400007d8; +ets_ds_start_sign = 0x400007dc; +ets_ds_is_busy = 0x400007e0; +ets_ds_finish_sign = 0x400007e4; +ets_ds_encrypt_params = 0x400007e8; +ets_mgf1_sha256 = 0x400007ec; +/* Data (.data, .bss, .rodata) */ +crc32_le_table_ptr = 0x4004fff8; +crc16_le_table_ptr = 0x4004fff4; +crc8_le_table_ptr = 0x4004fff0; +crc32_be_table_ptr = 0x4004ffec; +crc16_be_table_ptr = 0x4004ffe8; +crc8_be_table_ptr = 0x4004ffe4; + + +/*************************************** + Group efuse + ***************************************/ + +/* Functions */ +ets_efuse_read = 0x400007f0; +ets_efuse_program = 0x400007f4; +ets_efuse_clear_program_registers = 0x400007f8; +ets_efuse_write_key = 0x400007fc; +ets_efuse_get_read_register_address = 0x40000800; +ets_efuse_get_key_purpose = 0x40000804; +ets_efuse_key_block_unused = 0x40000808; +ets_efuse_find_unused_key_block = 0x4000080c; +ets_efuse_rs_calculate = 0x40000810; +ets_efuse_count_unused_key_blocks = 0x40000814; +ets_efuse_secure_boot_enabled = 0x40000818; +ets_efuse_secure_boot_aggressive_revoke_enabled = 0x4000081c; +ets_efuse_cache_encryption_enabled = 0x40000820; +ets_efuse_download_modes_disabled = 0x40000824; +ets_efuse_find_purpose = 0x40000828; +ets_efuse_force_send_resume = 0x4000082c; +ets_efuse_get_flash_delay_us = 0x40000830; +ets_efuse_get_uart_print_control = 0x40000834; +ets_efuse_direct_boot_mode_disabled = 0x40000838; +ets_efuse_security_download_modes_enabled = 0x4000083c; +ets_efuse_jtag_disabled = 0x40000840; +ets_efuse_usb_print_is_disabled = 0x40000844; +ets_efuse_usb_download_mode_disabled = 0x40000848; +ets_efuse_usb_device_disabled = 0x4000084c; +ets_efuse_secure_boot_fast_wake_enabled = 0x40000850; + + +/*************************************** + Group secureboot + ***************************************/ + +/* Functions */ +ets_emsa_pss_verify = 0x40000854; +ets_rsa_pss_verify = 0x40000858; +ets_ecdsa_verify = 0x4000085c; +ets_secure_boot_verify_bootloader_with_keys = 0x40000860; +ets_secure_boot_verify_signature = 0x40000864; +ets_secure_boot_read_key_digests = 0x40000868; +ets_secure_boot_revoke_public_key_digest = 0x4000086c; + + +/*************************************** + Group usb_device_uart + ***************************************/ + +/* Functions */ +usb_serial_device_rx_one_char = 0x40000a6c; +usb_serial_device_rx_one_char_block = 0x40000a70; +usb_serial_device_tx_flush = 0x40000a74; +usb_serial_device_tx_one_char = 0x40000a78; + diff --git a/flasher_stub/ld/stub_32c5_beta_3.ld b/flasher_stub/ld/stub_32c5_beta_3.ld new file mode 100644 index 000000000..e1133674e --- /dev/null +++ b/flasher_stub/ld/stub_32c5_beta_3.ld @@ -0,0 +1,26 @@ +MEMORY { + iram : org = 0x40800000, len = 0x4000 + dram : org = 0x40840000, len = 0x18000 +} + +ENTRY(stub_main) + +SECTIONS { + .text : ALIGN(4) { + *(.literal) + *(.text .text.*) + } > iram + + .bss : ALIGN(4) { + _bss_start = ABSOLUTE(.); + *(.bss) + _bss_end = ABSOLUTE(.); + } > dram + + .data : ALIGN(4) { + *(.data) + *(.rodata .rodata.*) + } > dram +} + +INCLUDE "rom_32c5_beta_3.ld" diff --git a/flasher_stub/stub_flasher.c b/flasher_stub/stub_flasher.c index 6b5885039..967bff5ec 100644 --- a/flasher_stub/stub_flasher.c +++ b/flasher_stub/stub_flasher.c @@ -63,7 +63,7 @@ static bool can_use_max_cpu_freq() #endif } -#if ESP32C6 || ESP32H2 +#if ESP32C6 || ESP32H2 || ESP32C5BETA3 static uint32_t pcr_sysclk_conf_reg = 0; #else static uint32_t cpu_per_conf_reg = 0; @@ -75,7 +75,7 @@ static void set_max_cpu_freq() if (can_use_max_cpu_freq()) { /* Set CPU frequency to max. This also increases SPI speed. */ - #if ESP32C6 || ESP32H2 + #if ESP32C6 || ESP32H2 || ESP32C5BETA3 pcr_sysclk_conf_reg = READ_REG(PCR_SYSCLK_CONF_REG); WRITE_REG(PCR_SYSCLK_CONF_REG, (pcr_sysclk_conf_reg & ~PCR_SOC_CLK_SEL_M) | (PCR_SOC_CLK_MAX << PCR_SOC_CLK_SEL_S)); #else @@ -92,7 +92,7 @@ static void reset_cpu_freq() { /* Restore saved sysclk_conf and cpu_per_conf registers. Use only if set_max_cpu_freq() has been called. */ - #if ESP32C6 || ESP32H2 + #if ESP32C6 || ESP32H2 || ESP32C5BETA3 if (can_use_max_cpu_freq() && pcr_sysclk_conf_reg != 0) { WRITE_REG(PCR_SYSCLK_CONF_REG, (READ_REG(PCR_SYSCLK_CONF_REG) & ~PCR_SOC_CLK_SEL_M) | (pcr_sysclk_conf_reg & PCR_SOC_CLK_SEL_M));