Add Code
This commit is contained in:
1162
code/.venv/lib/python3.12/site-packages/esptool/__init__.py
Normal file
1162
code/.venv/lib/python3.12/site-packages/esptool/__init__.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,9 @@
|
||||
# SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton,
|
||||
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
import esptool
|
||||
|
||||
if __name__ == "__main__":
|
||||
esptool._main()
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
1317
code/.venv/lib/python3.12/site-packages/esptool/bin_image.py
Normal file
1317
code/.venv/lib/python3.12/site-packages/esptool/bin_image.py
Normal file
File diff suppressed because it is too large
Load Diff
1357
code/.venv/lib/python3.12/site-packages/esptool/cmds.py
Normal file
1357
code/.venv/lib/python3.12/site-packages/esptool/cmds.py
Normal file
File diff suppressed because it is too large
Load Diff
92
code/.venv/lib/python3.12/site-packages/esptool/config.py
Normal file
92
code/.venv/lib/python3.12/site-packages/esptool/config.py
Normal file
@@ -0,0 +1,92 @@
|
||||
# SPDX-FileCopyrightText: 2014-2023 Espressif Systems (Shanghai) CO LTD,
|
||||
# other contributors as noted.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
import configparser
|
||||
import os
|
||||
|
||||
CONFIG_OPTIONS = [
|
||||
"timeout",
|
||||
"chip_erase_timeout",
|
||||
"max_timeout",
|
||||
"sync_timeout",
|
||||
"md5_timeout_per_mb",
|
||||
"erase_region_timeout_per_mb",
|
||||
"erase_write_timeout_per_mb",
|
||||
"mem_end_rom_timeout",
|
||||
"serial_write_timeout",
|
||||
"connect_attempts",
|
||||
"write_block_attempts",
|
||||
"reset_delay",
|
||||
"custom_reset_sequence",
|
||||
]
|
||||
|
||||
|
||||
def _validate_config_file(file_path, verbose=False):
|
||||
if not os.path.exists(file_path):
|
||||
return False
|
||||
|
||||
cfg = configparser.RawConfigParser()
|
||||
try:
|
||||
cfg.read(file_path, encoding="UTF-8")
|
||||
# Only consider it a valid config file if it contains [esptool] section
|
||||
if cfg.has_section("esptool"):
|
||||
if verbose:
|
||||
unknown_opts = list(set(cfg.options("esptool")) - set(CONFIG_OPTIONS))
|
||||
unknown_opts.sort()
|
||||
no_of_unknown_opts = len(unknown_opts)
|
||||
if no_of_unknown_opts > 0:
|
||||
suffix = "s" if no_of_unknown_opts > 1 else ""
|
||||
print(
|
||||
"Ignoring unknown config file option{}: {}".format(
|
||||
suffix, ", ".join(unknown_opts)
|
||||
)
|
||||
)
|
||||
return True
|
||||
except (UnicodeDecodeError, configparser.Error) as e:
|
||||
if verbose:
|
||||
print(f"Ignoring invalid config file {file_path}: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def _find_config_file(dir_path, verbose=False):
|
||||
for candidate in ("esptool.cfg", "setup.cfg", "tox.ini"):
|
||||
cfg_path = os.path.join(dir_path, candidate)
|
||||
if _validate_config_file(cfg_path, verbose):
|
||||
return cfg_path
|
||||
return None
|
||||
|
||||
|
||||
def load_config_file(verbose=False):
|
||||
set_with_env_var = False
|
||||
env_var_path = os.environ.get("ESPTOOL_CFGFILE")
|
||||
if env_var_path is not None and _validate_config_file(env_var_path):
|
||||
cfg_file_path = env_var_path
|
||||
set_with_env_var = True
|
||||
else:
|
||||
home_dir = os.path.expanduser("~")
|
||||
os_config_dir = (
|
||||
f"{home_dir}/.config/esptool"
|
||||
if os.name == "posix"
|
||||
else f"{home_dir}/AppData/Local/esptool/"
|
||||
)
|
||||
# Search priority: 1) current dir, 2) OS specific config dir, 3) home dir
|
||||
for dir_path in (os.getcwd(), os_config_dir, home_dir):
|
||||
cfg_file_path = _find_config_file(dir_path, verbose)
|
||||
if cfg_file_path:
|
||||
break
|
||||
|
||||
cfg = configparser.ConfigParser()
|
||||
cfg["esptool"] = {} # Create an empty esptool config for when no file is found
|
||||
|
||||
if cfg_file_path is not None:
|
||||
# If config file is found and validated, read and parse it
|
||||
cfg.read(cfg_file_path)
|
||||
if verbose:
|
||||
msg = " (set with ESPTOOL_CFGFILE)" if set_with_env_var else ""
|
||||
print(
|
||||
f"Loaded custom configuration from "
|
||||
f"{os.path.abspath(cfg_file_path)}{msg}"
|
||||
)
|
||||
return cfg, cfg_file_path
|
||||
1655
code/.venv/lib/python3.12/site-packages/esptool/loader.py
Normal file
1655
code/.venv/lib/python3.12/site-packages/esptool/loader.py
Normal file
File diff suppressed because it is too large
Load Diff
178
code/.venv/lib/python3.12/site-packages/esptool/reset.py
Normal file
178
code/.venv/lib/python3.12/site-packages/esptool/reset.py
Normal file
@@ -0,0 +1,178 @@
|
||||
# SPDX-FileCopyrightText: 2014-2023 Fredrik Ahlberg, Angus Gratton,
|
||||
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
import os
|
||||
import struct
|
||||
import time
|
||||
|
||||
from .util import FatalError
|
||||
|
||||
# Used for resetting into bootloader on Unix-like systems
|
||||
if os.name != "nt":
|
||||
import fcntl
|
||||
import termios
|
||||
|
||||
# Constants used for terminal status lines reading/setting.
|
||||
# Taken from pySerial's backend for IO:
|
||||
# https://github.com/pyserial/pyserial/blob/master/serial/serialposix.py
|
||||
TIOCMSET = getattr(termios, "TIOCMSET", 0x5418)
|
||||
TIOCMGET = getattr(termios, "TIOCMGET", 0x5415)
|
||||
TIOCM_DTR = getattr(termios, "TIOCM_DTR", 0x002)
|
||||
TIOCM_RTS = getattr(termios, "TIOCM_RTS", 0x004)
|
||||
|
||||
DEFAULT_RESET_DELAY = 0.05 # default time to wait before releasing boot pin after reset
|
||||
|
||||
|
||||
class ResetStrategy(object):
|
||||
def __init__(self, port, reset_delay=DEFAULT_RESET_DELAY):
|
||||
self.port = port
|
||||
self.reset_delay = reset_delay
|
||||
|
||||
def __call__():
|
||||
pass
|
||||
|
||||
def _setDTR(self, state):
|
||||
self.port.setDTR(state)
|
||||
|
||||
def _setRTS(self, state):
|
||||
self.port.setRTS(state)
|
||||
# Work-around for adapters on Windows using the usbser.sys driver:
|
||||
# generate a dummy change to DTR so that the set-control-line-state
|
||||
# request is sent with the updated RTS state and the same DTR state
|
||||
self.port.setDTR(self.port.dtr)
|
||||
|
||||
def _setDTRandRTS(self, dtr=False, rts=False):
|
||||
status = struct.unpack(
|
||||
"I", fcntl.ioctl(self.port.fileno(), TIOCMGET, struct.pack("I", 0))
|
||||
)[0]
|
||||
if dtr:
|
||||
status |= TIOCM_DTR
|
||||
else:
|
||||
status &= ~TIOCM_DTR
|
||||
if rts:
|
||||
status |= TIOCM_RTS
|
||||
else:
|
||||
status &= ~TIOCM_RTS
|
||||
fcntl.ioctl(self.port.fileno(), TIOCMSET, struct.pack("I", status))
|
||||
|
||||
|
||||
class ClassicReset(ResetStrategy):
|
||||
"""
|
||||
Classic reset sequence, sets DTR and RTS lines sequentially.
|
||||
"""
|
||||
|
||||
def __call__(self):
|
||||
self._setDTR(False) # IO0=HIGH
|
||||
self._setRTS(True) # EN=LOW, chip in reset
|
||||
time.sleep(0.1)
|
||||
self._setDTR(True) # IO0=LOW
|
||||
self._setRTS(False) # EN=HIGH, chip out of reset
|
||||
time.sleep(self.reset_delay)
|
||||
self._setDTR(False) # IO0=HIGH, done
|
||||
|
||||
|
||||
class UnixTightReset(ResetStrategy):
|
||||
"""
|
||||
UNIX-only reset sequence with custom implementation,
|
||||
which allows setting DTR and RTS lines at the same time.
|
||||
"""
|
||||
|
||||
def __call__(self):
|
||||
self._setDTRandRTS(False, False)
|
||||
self._setDTRandRTS(True, True)
|
||||
self._setDTRandRTS(False, True) # IO0=HIGH & EN=LOW, chip in reset
|
||||
time.sleep(0.1)
|
||||
self._setDTRandRTS(True, False) # IO0=LOW & EN=HIGH, chip out of reset
|
||||
time.sleep(self.reset_delay)
|
||||
self._setDTRandRTS(False, False) # IO0=HIGH, done
|
||||
self._setDTR(False) # Needed in some environments to ensure IO0=HIGH
|
||||
|
||||
|
||||
class USBJTAGSerialReset(ResetStrategy):
|
||||
"""
|
||||
Custom reset sequence, which is required when the device
|
||||
is connecting via its USB-JTAG-Serial peripheral.
|
||||
"""
|
||||
|
||||
def __call__(self):
|
||||
self._setRTS(False)
|
||||
self._setDTR(False) # Idle
|
||||
time.sleep(0.1)
|
||||
self._setDTR(True) # Set IO0
|
||||
self._setRTS(False)
|
||||
time.sleep(0.1)
|
||||
self._setRTS(True) # Reset. Calls inverted to go through (1,1) instead of (0,0)
|
||||
self._setDTR(False)
|
||||
self._setRTS(True) # RTS set as Windows only propagates DTR on RTS setting
|
||||
time.sleep(0.1)
|
||||
self._setDTR(False)
|
||||
self._setRTS(False) # Chip out of reset
|
||||
|
||||
|
||||
class HardReset(ResetStrategy):
|
||||
"""
|
||||
Reset sequence for hard resetting the chip.
|
||||
Can be used to reset out of the bootloader or to restart a running app.
|
||||
"""
|
||||
|
||||
def __init__(self, port, uses_usb_otg=False):
|
||||
super().__init__(port)
|
||||
self.uses_usb_otg = uses_usb_otg
|
||||
|
||||
def __call__(self):
|
||||
self._setRTS(True) # EN->LOW
|
||||
if self.uses_usb_otg:
|
||||
# Give the chip some time to come out of reset,
|
||||
# to be able to handle further DTR/RTS transitions
|
||||
time.sleep(0.2)
|
||||
self._setRTS(False)
|
||||
time.sleep(0.2)
|
||||
else:
|
||||
time.sleep(0.1)
|
||||
self._setRTS(False)
|
||||
|
||||
|
||||
class CustomReset(ResetStrategy):
|
||||
"""
|
||||
Custom reset strategy defined with a string.
|
||||
|
||||
CustomReset object is created as "rst = CustomReset(port, seq_str)"
|
||||
and can be later executed simply with "rst()"
|
||||
|
||||
The seq_str input string consists of individual commands divided by "|".
|
||||
Commands (e.g. R0) are defined by a code (R) and an argument (0).
|
||||
|
||||
The commands are:
|
||||
D: setDTR - 1=True / 0=False
|
||||
R: setRTS - 1=True / 0=False
|
||||
U: setDTRandRTS (Unix-only) - 0,0 / 0,1 / 1,0 / or 1,1
|
||||
W: Wait (time delay) - positive float number
|
||||
|
||||
e.g.
|
||||
"D0|R1|W0.1|D1|R0|W0.05|D0" represents the ClassicReset strategy
|
||||
"U1,1|U0,1|W0.1|U1,0|W0.05|U0,0" represents the UnixTightReset strategy
|
||||
"""
|
||||
|
||||
format_dict = {
|
||||
"D": "self.port.setDTR({})",
|
||||
"R": "self.port.setRTS({})",
|
||||
"W": "time.sleep({})",
|
||||
"U": "self._setDTRandRTS({})",
|
||||
}
|
||||
|
||||
def __call__(self):
|
||||
exec(self.constructed_strategy)
|
||||
|
||||
def __init__(self, port, seq_str):
|
||||
super().__init__(port)
|
||||
self.constructed_strategy = self._parse_string_to_seq(seq_str)
|
||||
|
||||
def _parse_string_to_seq(self, seq_str):
|
||||
try:
|
||||
cmds = seq_str.split("|")
|
||||
fn_calls_list = [self.format_dict[cmd[0]].format(cmd[1:]) for cmd in cmds]
|
||||
except Exception as e:
|
||||
raise FatalError(f'Invalid "custom_reset_sequence" option format: {e}')
|
||||
return "\n".join(fn_calls_list)
|
||||
@@ -0,0 +1,33 @@
|
||||
from .esp32 import ESP32ROM
|
||||
from .esp32c2 import ESP32C2ROM
|
||||
from .esp32c3 import ESP32C3ROM
|
||||
from .esp32c6 import ESP32C6ROM
|
||||
from .esp32c6beta import ESP32C6BETAROM
|
||||
from .esp32h2 import ESP32H2ROM
|
||||
from .esp32h2beta1 import ESP32H2BETA1ROM
|
||||
from .esp32h2beta2 import ESP32H2BETA2ROM
|
||||
from .esp32p4 import ESP32P4ROM
|
||||
from .esp32s2 import ESP32S2ROM
|
||||
from .esp32s3 import ESP32S3ROM
|
||||
from .esp32s3beta2 import ESP32S3BETA2ROM
|
||||
from .esp8266 import ESP8266ROM
|
||||
|
||||
|
||||
CHIP_DEFS = {
|
||||
"esp8266": ESP8266ROM,
|
||||
"esp32": ESP32ROM,
|
||||
"esp32s2": ESP32S2ROM,
|
||||
"esp32s3beta2": ESP32S3BETA2ROM,
|
||||
"esp32s3": ESP32S3ROM,
|
||||
"esp32c3": ESP32C3ROM,
|
||||
"esp32c6beta": ESP32C6BETAROM,
|
||||
"esp32h2beta1": ESP32H2BETA1ROM,
|
||||
"esp32h2beta2": ESP32H2BETA2ROM,
|
||||
"esp32c2": ESP32C2ROM,
|
||||
"esp32c6": ESP32C6ROM,
|
||||
"esp32h2": ESP32H2ROM,
|
||||
"esp32p4": ESP32P4ROM,
|
||||
}
|
||||
|
||||
CHIP_LIST = list(CHIP_DEFS.keys())
|
||||
ROM_LIST = list(CHIP_DEFS.values())
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
401
code/.venv/lib/python3.12/site-packages/esptool/targets/esp32.py
Normal file
401
code/.venv/lib/python3.12/site-packages/esptool/targets/esp32.py
Normal file
@@ -0,0 +1,401 @@
|
||||
# SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton,
|
||||
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
import struct
|
||||
import time
|
||||
|
||||
from ..loader import ESPLoader
|
||||
from ..util import FatalError, NotSupportedError
|
||||
|
||||
|
||||
class ESP32ROM(ESPLoader):
|
||||
"""Access class for ESP32 ROM bootloader"""
|
||||
|
||||
CHIP_NAME = "ESP32"
|
||||
IMAGE_CHIP_ID = 0
|
||||
IS_STUB = False
|
||||
|
||||
CHIP_DETECT_MAGIC_VALUE = [0x00F01D83]
|
||||
|
||||
IROM_MAP_START = 0x400D0000
|
||||
IROM_MAP_END = 0x40400000
|
||||
|
||||
DROM_MAP_START = 0x3F400000
|
||||
DROM_MAP_END = 0x3F800000
|
||||
|
||||
# ESP32 uses a 4 byte status reply
|
||||
STATUS_BYTES_LENGTH = 4
|
||||
|
||||
SPI_REG_BASE = 0x3FF42000
|
||||
SPI_USR_OFFS = 0x1C
|
||||
SPI_USR1_OFFS = 0x20
|
||||
SPI_USR2_OFFS = 0x24
|
||||
SPI_MOSI_DLEN_OFFS = 0x28
|
||||
SPI_MISO_DLEN_OFFS = 0x2C
|
||||
EFUSE_RD_REG_BASE = 0x3FF5A000
|
||||
|
||||
EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT_REG = EFUSE_RD_REG_BASE + 0x18
|
||||
EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT = 1 << 7 # EFUSE_RD_DISABLE_DL_ENCRYPT
|
||||
|
||||
EFUSE_SPI_BOOT_CRYPT_CNT_REG = EFUSE_RD_REG_BASE # EFUSE_BLK0_WDATA0_REG
|
||||
EFUSE_SPI_BOOT_CRYPT_CNT_MASK = 0x7F << 20 # EFUSE_FLASH_CRYPT_CNT
|
||||
|
||||
EFUSE_RD_ABS_DONE_REG = EFUSE_RD_REG_BASE + 0x018
|
||||
EFUSE_RD_ABS_DONE_0_MASK = 1 << 4
|
||||
EFUSE_RD_ABS_DONE_1_MASK = 1 << 5
|
||||
|
||||
DR_REG_SYSCON_BASE = 0x3FF66000
|
||||
APB_CTL_DATE_ADDR = DR_REG_SYSCON_BASE + 0x7C
|
||||
APB_CTL_DATE_V = 0x1
|
||||
APB_CTL_DATE_S = 31
|
||||
|
||||
SPI_W0_OFFS = 0x80
|
||||
|
||||
UART_CLKDIV_REG = 0x3FF40014
|
||||
|
||||
XTAL_CLK_DIVIDER = 1
|
||||
|
||||
RTCCALICFG1 = 0x3FF5F06C
|
||||
TIMERS_RTC_CALI_VALUE = 0x01FFFFFF
|
||||
TIMERS_RTC_CALI_VALUE_S = 7
|
||||
|
||||
FLASH_SIZES = {
|
||||
"1MB": 0x00,
|
||||
"2MB": 0x10,
|
||||
"4MB": 0x20,
|
||||
"8MB": 0x30,
|
||||
"16MB": 0x40,
|
||||
"32MB": 0x50,
|
||||
"64MB": 0x60,
|
||||
"128MB": 0x70,
|
||||
}
|
||||
|
||||
FLASH_FREQUENCY = {
|
||||
"80m": 0xF,
|
||||
"40m": 0x0,
|
||||
"26m": 0x1,
|
||||
"20m": 0x2,
|
||||
}
|
||||
|
||||
BOOTLOADER_FLASH_OFFSET = 0x1000
|
||||
|
||||
OVERRIDE_VDDSDIO_CHOICES = ["1.8V", "1.9V", "OFF"]
|
||||
|
||||
MEMORY_MAP = [
|
||||
[0x00000000, 0x00010000, "PADDING"],
|
||||
[0x3F400000, 0x3F800000, "DROM"],
|
||||
[0x3F800000, 0x3FC00000, "EXTRAM_DATA"],
|
||||
[0x3FF80000, 0x3FF82000, "RTC_DRAM"],
|
||||
[0x3FF90000, 0x40000000, "BYTE_ACCESSIBLE"],
|
||||
[0x3FFAE000, 0x40000000, "DRAM"],
|
||||
[0x3FFE0000, 0x3FFFFFFC, "DIRAM_DRAM"],
|
||||
[0x40000000, 0x40070000, "IROM"],
|
||||
[0x40070000, 0x40078000, "CACHE_PRO"],
|
||||
[0x40078000, 0x40080000, "CACHE_APP"],
|
||||
[0x40080000, 0x400A0000, "IRAM"],
|
||||
[0x400A0000, 0x400BFFFC, "DIRAM_IRAM"],
|
||||
[0x400C0000, 0x400C2000, "RTC_IRAM"],
|
||||
[0x400D0000, 0x40400000, "IROM"],
|
||||
[0x50000000, 0x50002000, "RTC_DATA"],
|
||||
]
|
||||
|
||||
FLASH_ENCRYPTED_WRITE_ALIGN = 32
|
||||
|
||||
UF2_FAMILY_ID = 0x1C5F21B0
|
||||
|
||||
""" Try to read the BLOCK1 (encryption key) and check if it is valid """
|
||||
|
||||
def is_flash_encryption_key_valid(self):
|
||||
"""Bit 0 of efuse_rd_disable[3:0] is mapped to BLOCK1
|
||||
this bit is at position 16 in EFUSE_BLK0_RDATA0_REG"""
|
||||
word0 = self.read_efuse(0)
|
||||
rd_disable = (word0 >> 16) & 0x1
|
||||
|
||||
# reading of BLOCK1 is NOT ALLOWED so we assume valid key is programmed
|
||||
if rd_disable:
|
||||
return True
|
||||
else:
|
||||
# reading of BLOCK1 is ALLOWED so we will read and verify for non-zero.
|
||||
# When ESP32 has not generated AES/encryption key in BLOCK1,
|
||||
# the contents will be readable and 0.
|
||||
# If the flash encryption is enabled it is expected to have a valid
|
||||
# non-zero key. We break out on first occurance of non-zero value
|
||||
key_word = [0] * 7
|
||||
for i in range(len(key_word)):
|
||||
key_word[i] = self.read_efuse(14 + i)
|
||||
# key is non-zero so break & return
|
||||
if key_word[i] != 0:
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_flash_crypt_config(self):
|
||||
"""For flash encryption related commands we need to make sure
|
||||
user has programmed all the relevant efuse correctly so before
|
||||
writing encrypted write_flash_encrypt esptool will verify the values
|
||||
of flash_crypt_config to be non zero if they are not read
|
||||
protected. If the values are zero a warning will be printed
|
||||
|
||||
bit 3 in efuse_rd_disable[3:0] is mapped to flash_crypt_config
|
||||
this bit is at position 19 in EFUSE_BLK0_RDATA0_REG"""
|
||||
word0 = self.read_efuse(0)
|
||||
rd_disable = (word0 >> 19) & 0x1
|
||||
|
||||
if rd_disable == 0:
|
||||
"""we can read the flash_crypt_config efuse value
|
||||
so go & read it (EFUSE_BLK0_RDATA5_REG[31:28])"""
|
||||
word5 = self.read_efuse(5)
|
||||
word5 = (word5 >> 28) & 0xF
|
||||
return word5
|
||||
else:
|
||||
# if read of the efuse is disabled we assume it is set correctly
|
||||
return 0xF
|
||||
|
||||
def get_encrypted_download_disabled(self):
|
||||
return (
|
||||
self.read_reg(self.EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT_REG)
|
||||
& self.EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT
|
||||
)
|
||||
|
||||
def get_flash_encryption_enabled(self):
|
||||
flash_crypt_cnt = (
|
||||
self.read_reg(self.EFUSE_SPI_BOOT_CRYPT_CNT_REG)
|
||||
& self.EFUSE_SPI_BOOT_CRYPT_CNT_MASK
|
||||
)
|
||||
# Flash encryption enabled when odd number of bits are set
|
||||
return bin(flash_crypt_cnt).count("1") & 1 != 0
|
||||
|
||||
def get_secure_boot_enabled(self):
|
||||
efuses = self.read_reg(self.EFUSE_RD_ABS_DONE_REG)
|
||||
rev = self.get_chip_revision()
|
||||
return efuses & self.EFUSE_RD_ABS_DONE_0_MASK or (
|
||||
rev >= 300 and efuses & self.EFUSE_RD_ABS_DONE_1_MASK
|
||||
)
|
||||
|
||||
def get_pkg_version(self):
|
||||
word3 = self.read_efuse(3)
|
||||
pkg_version = (word3 >> 9) & 0x07
|
||||
pkg_version += ((word3 >> 2) & 0x1) << 3
|
||||
return pkg_version
|
||||
|
||||
def get_chip_revision(self):
|
||||
return self.get_major_chip_version() * 100 + self.get_minor_chip_version()
|
||||
|
||||
def get_minor_chip_version(self):
|
||||
return (self.read_efuse(5) >> 24) & 0x3
|
||||
|
||||
def get_major_chip_version(self):
|
||||
rev_bit0 = (self.read_efuse(3) >> 15) & 0x1
|
||||
rev_bit1 = (self.read_efuse(5) >> 20) & 0x1
|
||||
apb_ctl_date = self.read_reg(self.APB_CTL_DATE_ADDR)
|
||||
rev_bit2 = (apb_ctl_date >> self.APB_CTL_DATE_S) & self.APB_CTL_DATE_V
|
||||
combine_value = (rev_bit2 << 2) | (rev_bit1 << 1) | rev_bit0
|
||||
|
||||
revision = {
|
||||
0: 0,
|
||||
1: 1,
|
||||
3: 2,
|
||||
7: 3,
|
||||
}.get(combine_value, 0)
|
||||
return revision
|
||||
|
||||
def get_chip_description(self):
|
||||
pkg_version = self.get_pkg_version()
|
||||
major_rev = self.get_major_chip_version()
|
||||
minor_rev = self.get_minor_chip_version()
|
||||
rev3 = major_rev == 3
|
||||
single_core = self.read_efuse(3) & (1 << 0) # CHIP_VER DIS_APP_CPU
|
||||
|
||||
chip_name = {
|
||||
0: "ESP32-S0WDQ6" if single_core else "ESP32-D0WDQ6",
|
||||
1: "ESP32-S0WD" if single_core else "ESP32-D0WD",
|
||||
2: "ESP32-D2WD",
|
||||
4: "ESP32-U4WDH",
|
||||
5: "ESP32-PICO-V3" if rev3 else "ESP32-PICO-D4",
|
||||
6: "ESP32-PICO-V3-02",
|
||||
7: "ESP32-D0WDR2-V3",
|
||||
}.get(pkg_version, "unknown ESP32")
|
||||
|
||||
# ESP32-D0WD-V3, ESP32-D0WDQ6-V3
|
||||
if chip_name.startswith("ESP32-D0WD") and rev3:
|
||||
chip_name += "-V3"
|
||||
|
||||
return f"{chip_name} (revision v{major_rev}.{minor_rev})"
|
||||
|
||||
def get_chip_features(self):
|
||||
features = ["WiFi"]
|
||||
word3 = self.read_efuse(3)
|
||||
|
||||
# names of variables in this section are lowercase
|
||||
# versions of EFUSE names as documented in TRM and
|
||||
# ESP-IDF efuse_reg.h
|
||||
|
||||
chip_ver_dis_bt = word3 & (1 << 1)
|
||||
if chip_ver_dis_bt == 0:
|
||||
features += ["BT"]
|
||||
|
||||
chip_ver_dis_app_cpu = word3 & (1 << 0)
|
||||
if chip_ver_dis_app_cpu:
|
||||
features += ["Single Core"]
|
||||
else:
|
||||
features += ["Dual Core"]
|
||||
|
||||
chip_cpu_freq_rated = word3 & (1 << 13)
|
||||
if chip_cpu_freq_rated:
|
||||
chip_cpu_freq_low = word3 & (1 << 12)
|
||||
if chip_cpu_freq_low:
|
||||
features += ["160MHz"]
|
||||
else:
|
||||
features += ["240MHz"]
|
||||
|
||||
pkg_version = self.get_pkg_version()
|
||||
if pkg_version in [2, 4, 5, 6]:
|
||||
features += ["Embedded Flash"]
|
||||
|
||||
if pkg_version == 6:
|
||||
features += ["Embedded PSRAM"]
|
||||
|
||||
word4 = self.read_efuse(4)
|
||||
adc_vref = (word4 >> 8) & 0x1F
|
||||
if adc_vref:
|
||||
features += ["VRef calibration in efuse"]
|
||||
|
||||
blk3_part_res = word3 >> 14 & 0x1
|
||||
if blk3_part_res:
|
||||
features += ["BLK3 partially reserved"]
|
||||
|
||||
word6 = self.read_efuse(6)
|
||||
coding_scheme = word6 & 0x3
|
||||
features += [
|
||||
"Coding Scheme %s"
|
||||
% {0: "None", 1: "3/4", 2: "Repeat (UNSUPPORTED)", 3: "Invalid"}[
|
||||
coding_scheme
|
||||
]
|
||||
]
|
||||
|
||||
return features
|
||||
|
||||
def read_efuse(self, n):
|
||||
"""Read the nth word of the ESP3x EFUSE region."""
|
||||
return self.read_reg(self.EFUSE_RD_REG_BASE + (4 * n))
|
||||
|
||||
def chip_id(self):
|
||||
raise NotSupportedError(self, "Function chip_id")
|
||||
|
||||
def read_mac(self, mac_type="BASE_MAC"):
|
||||
"""Read MAC from EFUSE region"""
|
||||
if mac_type != "BASE_MAC":
|
||||
return None
|
||||
words = [self.read_efuse(2), self.read_efuse(1)]
|
||||
bitstring = struct.pack(">II", *words)
|
||||
bitstring = bitstring[2:8] # trim the 2 byte CRC
|
||||
return tuple(bitstring)
|
||||
|
||||
def get_erase_size(self, offset, size):
|
||||
return size
|
||||
|
||||
def override_vddsdio(self, new_voltage):
|
||||
new_voltage = new_voltage.upper()
|
||||
if new_voltage not in self.OVERRIDE_VDDSDIO_CHOICES:
|
||||
raise FatalError(
|
||||
"The only accepted VDDSDIO overrides are '1.8V', '1.9V' and 'OFF'"
|
||||
)
|
||||
RTC_CNTL_SDIO_CONF_REG = 0x3FF48074
|
||||
RTC_CNTL_XPD_SDIO_REG = 1 << 31
|
||||
RTC_CNTL_DREFH_SDIO_M = 3 << 29
|
||||
RTC_CNTL_DREFM_SDIO_M = 3 << 27
|
||||
RTC_CNTL_DREFL_SDIO_M = 3 << 25
|
||||
# RTC_CNTL_SDIO_TIEH = (1 << 23)
|
||||
# not used here, setting TIEH=1 would set 3.3V output,
|
||||
# not safe for esptool.py to do
|
||||
RTC_CNTL_SDIO_FORCE = 1 << 22
|
||||
RTC_CNTL_SDIO_PD_EN = 1 << 21
|
||||
|
||||
reg_val = RTC_CNTL_SDIO_FORCE # override efuse setting
|
||||
reg_val |= RTC_CNTL_SDIO_PD_EN
|
||||
if new_voltage != "OFF":
|
||||
reg_val |= RTC_CNTL_XPD_SDIO_REG # enable internal LDO
|
||||
if new_voltage == "1.9V":
|
||||
reg_val |= (
|
||||
RTC_CNTL_DREFH_SDIO_M | RTC_CNTL_DREFM_SDIO_M | RTC_CNTL_DREFL_SDIO_M
|
||||
) # boost voltage
|
||||
self.write_reg(RTC_CNTL_SDIO_CONF_REG, reg_val)
|
||||
print("VDDSDIO regulator set to %s" % new_voltage)
|
||||
|
||||
def read_flash_slow(self, offset, length, progress_fn):
|
||||
BLOCK_LEN = 64 # ROM read limit per command (this limit is why it's so slow)
|
||||
|
||||
data = b""
|
||||
while len(data) < length:
|
||||
block_len = min(BLOCK_LEN, length - len(data))
|
||||
r = self.check_command(
|
||||
"read flash block",
|
||||
self.ESP_READ_FLASH_SLOW,
|
||||
struct.pack("<II", offset + len(data), block_len),
|
||||
)
|
||||
if len(r) < block_len:
|
||||
raise FatalError(
|
||||
"Expected %d byte block, got %d bytes. Serial errors?"
|
||||
% (block_len, len(r))
|
||||
)
|
||||
# command always returns 64 byte buffer,
|
||||
# regardless of how many bytes were actually read from flash
|
||||
data += r[:block_len]
|
||||
if progress_fn and (len(data) % 1024 == 0 or len(data) == length):
|
||||
progress_fn(len(data), length)
|
||||
return data
|
||||
|
||||
def get_rom_cal_crystal_freq(self):
|
||||
"""
|
||||
Get the crystal frequency calculated by the ROM
|
||||
"""
|
||||
# - Simulate the calculation in the ROM to get the XTAL frequency
|
||||
# calculated by the ROM
|
||||
|
||||
cali_val = (
|
||||
self.read_reg(self.RTCCALICFG1) >> self.TIMERS_RTC_CALI_VALUE_S
|
||||
) & self.TIMERS_RTC_CALI_VALUE
|
||||
clk_8M_freq = self.read_efuse(4) & (0xFF) # EFUSE_RD_CK8M_FREQ
|
||||
rom_calculated_freq = cali_val * 15625 * clk_8M_freq / 40
|
||||
return rom_calculated_freq
|
||||
|
||||
def change_baud(self, baud):
|
||||
assert self.CHIP_NAME == "ESP32", "This workaround should only apply to ESP32"
|
||||
# It's a workaround to avoid esp32 CK_8M frequency drift.
|
||||
rom_calculated_freq = self.get_rom_cal_crystal_freq()
|
||||
valid_freq = 40000000 if rom_calculated_freq > 33000000 else 26000000
|
||||
false_rom_baud = int(baud * rom_calculated_freq // valid_freq)
|
||||
|
||||
print(f"Changing baud rate to {baud}")
|
||||
self.command(self.ESP_CHANGE_BAUDRATE, struct.pack("<II", false_rom_baud, 0))
|
||||
print("Changed.")
|
||||
self._set_port_baudrate(baud)
|
||||
time.sleep(0.05) # get rid of garbage sent during baud rate change
|
||||
self.flush_input()
|
||||
|
||||
def check_spi_connection(self, spi_connection):
|
||||
# Pins 30, 31 do not exist
|
||||
if not set(spi_connection).issubset(set(range(0, 30)) | set((32, 33))):
|
||||
raise FatalError("SPI Pin numbers must be in the range 0-29, 32, or 33.")
|
||||
|
||||
|
||||
class ESP32StubLoader(ESP32ROM):
|
||||
"""Access class for ESP32 stub loader, runs on top of ROM."""
|
||||
|
||||
FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c
|
||||
STATUS_BYTES_LENGTH = 2 # same as ESP8266, different to ESP32 ROM
|
||||
IS_STUB = True
|
||||
|
||||
def __init__(self, rom_loader):
|
||||
self.secure_download_mode = rom_loader.secure_download_mode
|
||||
self._port = rom_loader._port
|
||||
self._trace_enabled = rom_loader._trace_enabled
|
||||
self.cache = rom_loader.cache
|
||||
self.flush_input() # resets _slip_reader
|
||||
|
||||
def change_baud(self, baud):
|
||||
ESPLoader.change_baud(self, baud)
|
||||
|
||||
|
||||
ESP32ROM.STUB_CLASS = ESP32StubLoader
|
||||
@@ -0,0 +1,182 @@
|
||||
# SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton,
|
||||
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
import struct
|
||||
import time
|
||||
|
||||
from .esp32c3 import ESP32C3ROM
|
||||
from ..loader import ESPLoader
|
||||
from ..util import FatalError
|
||||
|
||||
|
||||
class ESP32C2ROM(ESP32C3ROM):
|
||||
CHIP_NAME = "ESP32-C2"
|
||||
IMAGE_CHIP_ID = 12
|
||||
|
||||
IROM_MAP_START = 0x42000000
|
||||
IROM_MAP_END = 0x42400000
|
||||
DROM_MAP_START = 0x3C000000
|
||||
DROM_MAP_END = 0x3C400000
|
||||
|
||||
# Magic value for ESP32C2 ECO0 and ECO1 respectively
|
||||
CHIP_DETECT_MAGIC_VALUE = [0x6F51306F, 0x7C41A06F]
|
||||
|
||||
EFUSE_BASE = 0x60008800
|
||||
EFUSE_BLOCK2_ADDR = EFUSE_BASE + 0x040
|
||||
MAC_EFUSE_REG = EFUSE_BASE + 0x040
|
||||
|
||||
EFUSE_SECURE_BOOT_EN_REG = EFUSE_BASE + 0x30
|
||||
EFUSE_SECURE_BOOT_EN_MASK = 1 << 21
|
||||
|
||||
EFUSE_SPI_BOOT_CRYPT_CNT_REG = EFUSE_BASE + 0x30
|
||||
EFUSE_SPI_BOOT_CRYPT_CNT_MASK = 0x7 << 18
|
||||
|
||||
EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT_REG = EFUSE_BASE + 0x30
|
||||
EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT = 1 << 6
|
||||
|
||||
EFUSE_XTS_KEY_LENGTH_256_REG = EFUSE_BASE + 0x30
|
||||
EFUSE_XTS_KEY_LENGTH_256 = 1 << 10
|
||||
|
||||
EFUSE_BLOCK_KEY0_REG = EFUSE_BASE + 0x60
|
||||
|
||||
EFUSE_RD_DIS_REG = EFUSE_BASE + 0x30
|
||||
EFUSE_RD_DIS = 3
|
||||
|
||||
FLASH_FREQUENCY = {
|
||||
"60m": 0xF,
|
||||
"30m": 0x0,
|
||||
"20m": 0x1,
|
||||
"15m": 0x2,
|
||||
}
|
||||
|
||||
MEMORY_MAP = [
|
||||
[0x00000000, 0x00010000, "PADDING"],
|
||||
[0x3C000000, 0x3C400000, "DROM"],
|
||||
[0x3FCA0000, 0x3FCE0000, "DRAM"],
|
||||
[0x3FC88000, 0x3FD00000, "BYTE_ACCESSIBLE"],
|
||||
[0x3FF00000, 0x3FF50000, "DROM_MASK"],
|
||||
[0x40000000, 0x40090000, "IROM_MASK"],
|
||||
[0x42000000, 0x42400000, "IROM"],
|
||||
[0x4037C000, 0x403C0000, "IRAM"],
|
||||
]
|
||||
|
||||
UF2_FAMILY_ID = 0x2B88D29C
|
||||
|
||||
def get_pkg_version(self):
|
||||
num_word = 1
|
||||
return (self.read_reg(self.EFUSE_BLOCK2_ADDR + (4 * num_word)) >> 22) & 0x07
|
||||
|
||||
def get_chip_description(self):
|
||||
chip_name = {
|
||||
0: "ESP32-C2",
|
||||
1: "ESP32-C2",
|
||||
}.get(self.get_pkg_version(), "unknown ESP32-C2")
|
||||
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_minor_chip_version(self):
|
||||
num_word = 1
|
||||
return (self.read_reg(self.EFUSE_BLOCK2_ADDR + (4 * num_word)) >> 16) & 0xF
|
||||
|
||||
def get_major_chip_version(self):
|
||||
num_word = 1
|
||||
return (self.read_reg(self.EFUSE_BLOCK2_ADDR + (4 * num_word)) >> 20) & 0x3
|
||||
|
||||
def get_flash_cap(self):
|
||||
# ESP32-C2 doesn't have eFuse field FLASH_CAP.
|
||||
# Can't get info about the flash chip.
|
||||
return 0
|
||||
|
||||
def get_flash_vendor(self):
|
||||
# ESP32-C2 doesn't have eFuse field FLASH_VENDOR.
|
||||
# Can't get info about the flash chip.
|
||||
return ""
|
||||
|
||||
def get_crystal_freq(self):
|
||||
# The crystal detection algorithm of ESP32/ESP8266 works for ESP32-C2 as well.
|
||||
return ESPLoader.get_crystal_freq(self)
|
||||
|
||||
def change_baud(self, baud):
|
||||
rom_with_26M_XTAL = not self.IS_STUB and self.get_crystal_freq() == 26
|
||||
if rom_with_26M_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 26 MHz XTAL.
|
||||
false_rom_baud = baud * 40 // 26
|
||||
|
||||
print(f"Changing baud rate to {baud}")
|
||||
self.command(
|
||||
self.ESP_CHANGE_BAUDRATE, struct.pack("<II", false_rom_baud, 0)
|
||||
)
|
||||
print("Changed.")
|
||||
self._set_port_baudrate(baud)
|
||||
time.sleep(0.05) # get rid of garbage sent during baud rate change
|
||||
self.flush_input()
|
||||
else:
|
||||
ESPLoader.change_baud(self, baud)
|
||||
|
||||
def _post_connect(self):
|
||||
# ESP32C2 ECO0 is no longer supported by the flasher stub
|
||||
if not self.secure_download_mode and self.get_chip_revision() == 0:
|
||||
self.stub_is_disabled = True
|
||||
self.IS_STUB = False
|
||||
|
||||
""" Try to read (encryption key) and check if it is valid """
|
||||
|
||||
def is_flash_encryption_key_valid(self):
|
||||
key_len_256 = (
|
||||
self.read_reg(self.EFUSE_XTS_KEY_LENGTH_256_REG)
|
||||
& self.EFUSE_XTS_KEY_LENGTH_256
|
||||
)
|
||||
|
||||
word0 = self.read_reg(self.EFUSE_RD_DIS_REG) & self.EFUSE_RD_DIS
|
||||
rd_disable = word0 == 3 if key_len_256 else word0 == 1
|
||||
|
||||
# reading of BLOCK3 is NOT ALLOWED so we assume valid key is programmed
|
||||
if rd_disable:
|
||||
return True
|
||||
else:
|
||||
# reading of BLOCK3 is ALLOWED so we will read and verify for non-zero.
|
||||
# When chip has not generated AES/encryption key in BLOCK3,
|
||||
# the contents will be readable and 0.
|
||||
# If the flash encryption is enabled it is expected to have a valid
|
||||
# non-zero key. We break out on first occurance of non-zero value
|
||||
key_word = [0] * 7 if key_len_256 else [0] * 3
|
||||
for i in range(len(key_word)):
|
||||
key_word[i] = self.read_reg(self.EFUSE_BLOCK_KEY0_REG + i * 4)
|
||||
# key is non-zero so break & return
|
||||
if key_word[i] != 0:
|
||||
return True
|
||||
return False
|
||||
|
||||
def check_spi_connection(self, spi_connection):
|
||||
if not set(spi_connection).issubset(set(range(0, 21))):
|
||||
raise FatalError("SPI Pin numbers must be in the range 0-20.")
|
||||
|
||||
|
||||
class ESP32C2StubLoader(ESP32C2ROM):
|
||||
"""Access class for ESP32C2 stub loader, runs on top of ROM.
|
||||
|
||||
(Basically the same as ESP32StubLoader, but different base class.
|
||||
Can possibly be made into a mixin.)
|
||||
"""
|
||||
|
||||
FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c
|
||||
STATUS_BYTES_LENGTH = 2 # same as ESP8266, different to ESP32 ROM
|
||||
IS_STUB = True
|
||||
|
||||
def __init__(self, rom_loader):
|
||||
self.secure_download_mode = rom_loader.secure_download_mode
|
||||
self._port = rom_loader._port
|
||||
self._trace_enabled = rom_loader._trace_enabled
|
||||
self.cache = rom_loader.cache
|
||||
self.flush_input() # resets _slip_reader
|
||||
|
||||
|
||||
ESP32C2ROM.STUB_CLASS = ESP32C2StubLoader
|
||||
@@ -0,0 +1,260 @@
|
||||
# SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton,
|
||||
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
import struct
|
||||
|
||||
from .esp32 import ESP32ROM
|
||||
from ..loader import ESPLoader
|
||||
from ..util import FatalError, NotImplementedInROMError
|
||||
|
||||
|
||||
class ESP32C3ROM(ESP32ROM):
|
||||
CHIP_NAME = "ESP32-C3"
|
||||
IMAGE_CHIP_ID = 5
|
||||
|
||||
IROM_MAP_START = 0x42000000
|
||||
IROM_MAP_END = 0x42800000
|
||||
DROM_MAP_START = 0x3C000000
|
||||
DROM_MAP_END = 0x3C800000
|
||||
|
||||
SPI_REG_BASE = 0x60002000
|
||||
SPI_USR_OFFS = 0x18
|
||||
SPI_USR1_OFFS = 0x1C
|
||||
SPI_USR2_OFFS = 0x20
|
||||
SPI_MOSI_DLEN_OFFS = 0x24
|
||||
SPI_MISO_DLEN_OFFS = 0x28
|
||||
SPI_W0_OFFS = 0x58
|
||||
|
||||
BOOTLOADER_FLASH_OFFSET = 0x0
|
||||
|
||||
# Magic values for ESP32-C3 eco 1+2, eco 3, eco 6, and eco 7 respectively
|
||||
CHIP_DETECT_MAGIC_VALUE = [0x6921506F, 0x1B31506F, 0x4881606F, 0x4361606F]
|
||||
|
||||
UART_DATE_REG_ADDR = 0x60000000 + 0x7C
|
||||
|
||||
UART_CLKDIV_REG = 0x60000014
|
||||
|
||||
EFUSE_BASE = 0x60008800
|
||||
EFUSE_BLOCK1_ADDR = EFUSE_BASE + 0x044
|
||||
MAC_EFUSE_REG = EFUSE_BASE + 0x044
|
||||
|
||||
EFUSE_RD_REG_BASE = EFUSE_BASE + 0x030 # BLOCK0 read base address
|
||||
|
||||
EFUSE_PURPOSE_KEY0_REG = EFUSE_BASE + 0x34
|
||||
EFUSE_PURPOSE_KEY0_SHIFT = 24
|
||||
EFUSE_PURPOSE_KEY1_REG = EFUSE_BASE + 0x34
|
||||
EFUSE_PURPOSE_KEY1_SHIFT = 28
|
||||
EFUSE_PURPOSE_KEY2_REG = EFUSE_BASE + 0x38
|
||||
EFUSE_PURPOSE_KEY2_SHIFT = 0
|
||||
EFUSE_PURPOSE_KEY3_REG = EFUSE_BASE + 0x38
|
||||
EFUSE_PURPOSE_KEY3_SHIFT = 4
|
||||
EFUSE_PURPOSE_KEY4_REG = EFUSE_BASE + 0x38
|
||||
EFUSE_PURPOSE_KEY4_SHIFT = 8
|
||||
EFUSE_PURPOSE_KEY5_REG = EFUSE_BASE + 0x38
|
||||
EFUSE_PURPOSE_KEY5_SHIFT = 12
|
||||
|
||||
EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT_REG = EFUSE_RD_REG_BASE
|
||||
EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT = 1 << 20
|
||||
|
||||
EFUSE_SPI_BOOT_CRYPT_CNT_REG = EFUSE_BASE + 0x034
|
||||
EFUSE_SPI_BOOT_CRYPT_CNT_MASK = 0x7 << 18
|
||||
|
||||
EFUSE_SECURE_BOOT_EN_REG = EFUSE_BASE + 0x038
|
||||
EFUSE_SECURE_BOOT_EN_MASK = 1 << 20
|
||||
|
||||
PURPOSE_VAL_XTS_AES128_KEY = 4
|
||||
|
||||
SUPPORTS_ENCRYPTED_FLASH = True
|
||||
|
||||
FLASH_ENCRYPTED_WRITE_ALIGN = 16
|
||||
|
||||
UARTDEV_BUF_NO = 0x3FCDF07C # Variable in ROM .bss which indicates the port in use
|
||||
UARTDEV_BUF_NO_USB_JTAG_SERIAL = 3 # The above var when USB-JTAG/Serial is used
|
||||
|
||||
RTCCNTL_BASE_REG = 0x60008000
|
||||
RTC_CNTL_SWD_CONF_REG = RTCCNTL_BASE_REG + 0x00AC
|
||||
RTC_CNTL_SWD_AUTO_FEED_EN = 1 << 31
|
||||
RTC_CNTL_SWD_WPROTECT_REG = RTCCNTL_BASE_REG + 0x00B0
|
||||
RTC_CNTL_SWD_WKEY = 0x8F1D312A
|
||||
|
||||
RTC_CNTL_WDTCONFIG0_REG = RTCCNTL_BASE_REG + 0x0090
|
||||
RTC_CNTL_WDTWPROTECT_REG = RTCCNTL_BASE_REG + 0x00A8
|
||||
RTC_CNTL_WDT_WKEY = 0x50D83AA1
|
||||
|
||||
MEMORY_MAP = [
|
||||
[0x00000000, 0x00010000, "PADDING"],
|
||||
[0x3C000000, 0x3C800000, "DROM"],
|
||||
[0x3FC80000, 0x3FCE0000, "DRAM"],
|
||||
[0x3FC88000, 0x3FD00000, "BYTE_ACCESSIBLE"],
|
||||
[0x3FF00000, 0x3FF20000, "DROM_MASK"],
|
||||
[0x40000000, 0x40060000, "IROM_MASK"],
|
||||
[0x42000000, 0x42800000, "IROM"],
|
||||
[0x4037C000, 0x403E0000, "IRAM"],
|
||||
[0x50000000, 0x50002000, "RTC_IRAM"],
|
||||
[0x50000000, 0x50002000, "RTC_DRAM"],
|
||||
[0x600FE000, 0x60100000, "MEM_INTERNAL2"],
|
||||
]
|
||||
|
||||
UF2_FAMILY_ID = 0xD42BA06C
|
||||
|
||||
def get_pkg_version(self):
|
||||
num_word = 3
|
||||
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 21) & 0x07
|
||||
|
||||
def get_minor_chip_version(self):
|
||||
hi_num_word = 5
|
||||
hi = (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * hi_num_word)) >> 23) & 0x01
|
||||
low_num_word = 3
|
||||
low = (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * low_num_word)) >> 18) & 0x07
|
||||
return (hi << 3) + low
|
||||
|
||||
def get_major_chip_version(self):
|
||||
num_word = 5
|
||||
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 24) & 0x03
|
||||
|
||||
def get_flash_cap(self):
|
||||
num_word = 3
|
||||
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 27) & 0x07
|
||||
|
||||
def get_flash_vendor(self):
|
||||
num_word = 4
|
||||
vendor_id = (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 0) & 0x07
|
||||
return {1: "XMC", 2: "GD", 3: "FM", 4: "TT", 5: "ZBIT"}.get(vendor_id, "")
|
||||
|
||||
def get_chip_description(self):
|
||||
chip_name = {
|
||||
0: "ESP32-C3 (QFN32)",
|
||||
1: "ESP8685 (QFN28)",
|
||||
2: "ESP32-C3 AZ (QFN32)",
|
||||
3: "ESP8686 (QFN24)",
|
||||
}.get(self.get_pkg_version(), "unknown ESP32-C3")
|
||||
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_chip_features(self):
|
||||
features = ["WiFi", "BLE"]
|
||||
|
||||
flash = {
|
||||
0: None,
|
||||
1: "Embedded Flash 4MB",
|
||||
2: "Embedded Flash 2MB",
|
||||
3: "Embedded Flash 1MB",
|
||||
4: "Embedded Flash 8MB",
|
||||
}.get(self.get_flash_cap(), "Unknown Embedded Flash")
|
||||
if flash is not None:
|
||||
features += [flash + f" ({self.get_flash_vendor()})"]
|
||||
return features
|
||||
|
||||
def get_crystal_freq(self):
|
||||
# ESP32C3 XTAL is fixed to 40MHz
|
||||
return 40
|
||||
|
||||
def override_vddsdio(self, new_voltage):
|
||||
raise NotImplementedInROMError(
|
||||
"VDD_SDIO overrides are not supported for ESP32-C3"
|
||||
)
|
||||
|
||||
def read_mac(self, mac_type="BASE_MAC"):
|
||||
"""Read MAC from EFUSE region"""
|
||||
if mac_type != "BASE_MAC":
|
||||
return None
|
||||
mac0 = self.read_reg(self.MAC_EFUSE_REG)
|
||||
mac1 = self.read_reg(self.MAC_EFUSE_REG + 4) # only bottom 16 bits are MAC
|
||||
bitstring = struct.pack(">II", mac1, mac0)[2:]
|
||||
return tuple(bitstring)
|
||||
|
||||
def get_flash_crypt_config(self):
|
||||
return None # doesn't exist on ESP32-C3
|
||||
|
||||
def get_secure_boot_enabled(self):
|
||||
return (
|
||||
self.read_reg(self.EFUSE_SECURE_BOOT_EN_REG)
|
||||
& self.EFUSE_SECURE_BOOT_EN_MASK
|
||||
)
|
||||
|
||||
def get_key_block_purpose(self, key_block):
|
||||
if key_block < 0 or key_block > 5:
|
||||
raise FatalError("Valid key block numbers must be in range 0-5")
|
||||
|
||||
reg, shift = [
|
||||
(self.EFUSE_PURPOSE_KEY0_REG, self.EFUSE_PURPOSE_KEY0_SHIFT),
|
||||
(self.EFUSE_PURPOSE_KEY1_REG, self.EFUSE_PURPOSE_KEY1_SHIFT),
|
||||
(self.EFUSE_PURPOSE_KEY2_REG, self.EFUSE_PURPOSE_KEY2_SHIFT),
|
||||
(self.EFUSE_PURPOSE_KEY3_REG, self.EFUSE_PURPOSE_KEY3_SHIFT),
|
||||
(self.EFUSE_PURPOSE_KEY4_REG, self.EFUSE_PURPOSE_KEY4_SHIFT),
|
||||
(self.EFUSE_PURPOSE_KEY5_REG, self.EFUSE_PURPOSE_KEY5_SHIFT),
|
||||
][key_block]
|
||||
return (self.read_reg(reg) >> shift) & 0xF
|
||||
|
||||
def is_flash_encryption_key_valid(self):
|
||||
# Need to see an AES-128 key
|
||||
purposes = [self.get_key_block_purpose(b) for b in range(6)]
|
||||
|
||||
return any(p == self.PURPOSE_VAL_XTS_AES128_KEY for p in purposes)
|
||||
|
||||
def change_baud(self, baud):
|
||||
ESPLoader.change_baud(self, baud)
|
||||
|
||||
def uses_usb_jtag_serial(self):
|
||||
"""
|
||||
Check the UARTDEV_BUF_NO register to see if USB-JTAG/Serial is being used
|
||||
"""
|
||||
if self.secure_download_mode:
|
||||
return False # Can't detect USB-JTAG/Serial in secure download mode
|
||||
return self.get_uart_no() == self.UARTDEV_BUF_NO_USB_JTAG_SERIAL
|
||||
|
||||
def disable_watchdogs(self):
|
||||
# When USB-JTAG/Serial is used, the RTC WDT and SWD watchdog are not reset
|
||||
# and can then reset the board during flashing. Disable or autofeed them.
|
||||
if self.uses_usb_jtag_serial():
|
||||
# Disable RTC WDT
|
||||
self.write_reg(self.RTC_CNTL_WDTWPROTECT_REG, self.RTC_CNTL_WDT_WKEY)
|
||||
self.write_reg(self.RTC_CNTL_WDTCONFIG0_REG, 0)
|
||||
self.write_reg(self.RTC_CNTL_WDTWPROTECT_REG, 0)
|
||||
|
||||
# Automatically feed SWD
|
||||
self.write_reg(self.RTC_CNTL_SWD_WPROTECT_REG, self.RTC_CNTL_SWD_WKEY)
|
||||
self.write_reg(
|
||||
self.RTC_CNTL_SWD_CONF_REG,
|
||||
self.read_reg(self.RTC_CNTL_SWD_CONF_REG)
|
||||
| self.RTC_CNTL_SWD_AUTO_FEED_EN,
|
||||
)
|
||||
self.write_reg(self.RTC_CNTL_SWD_WPROTECT_REG, 0)
|
||||
|
||||
def _post_connect(self):
|
||||
if not self.sync_stub_detected: # Don't run if stub is reused
|
||||
self.disable_watchdogs()
|
||||
|
||||
def check_spi_connection(self, spi_connection):
|
||||
if not set(spi_connection).issubset(set(range(0, 22))):
|
||||
raise FatalError("SPI Pin numbers must be in the range 0-21.")
|
||||
if any([v for v in spi_connection if v in [18, 19]]):
|
||||
print(
|
||||
"WARNING: GPIO pins 18 and 19 are used by USB-Serial/JTAG, "
|
||||
"consider using other pins for SPI flash connection."
|
||||
)
|
||||
|
||||
|
||||
class ESP32C3StubLoader(ESP32C3ROM):
|
||||
"""Access class for ESP32C3 stub loader, runs on top of ROM.
|
||||
|
||||
(Basically the same as ESP32StubLoader, but different base class.
|
||||
Can possibly be made into a mixin.)
|
||||
"""
|
||||
|
||||
FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c
|
||||
STATUS_BYTES_LENGTH = 2 # same as ESP8266, different to ESP32 ROM
|
||||
IS_STUB = True
|
||||
|
||||
def __init__(self, rom_loader):
|
||||
self.secure_download_mode = rom_loader.secure_download_mode
|
||||
self._port = rom_loader._port
|
||||
self._trace_enabled = rom_loader._trace_enabled
|
||||
self.cache = rom_loader.cache
|
||||
self.flush_input() # resets _slip_reader
|
||||
|
||||
|
||||
ESP32C3ROM.STUB_CLASS = ESP32C3StubLoader
|
||||
@@ -0,0 +1,212 @@
|
||||
# SPDX-FileCopyrightText: 2022 Fredrik Ahlberg, Angus Gratton,
|
||||
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
import struct
|
||||
|
||||
from .esp32c3 import ESP32C3ROM
|
||||
from ..util import FatalError, NotImplementedInROMError
|
||||
|
||||
|
||||
class ESP32C6ROM(ESP32C3ROM):
|
||||
CHIP_NAME = "ESP32-C6"
|
||||
IMAGE_CHIP_ID = 13
|
||||
|
||||
IROM_MAP_START = 0x42000000
|
||||
IROM_MAP_END = 0x42800000
|
||||
DROM_MAP_START = 0x42800000
|
||||
DROM_MAP_END = 0x43000000
|
||||
|
||||
BOOTLOADER_FLASH_OFFSET = 0x0
|
||||
|
||||
# Magic value for ESP32C6
|
||||
CHIP_DETECT_MAGIC_VALUE = [0x2CE0806F]
|
||||
|
||||
SPI_REG_BASE = 0x60003000
|
||||
SPI_USR_OFFS = 0x18
|
||||
SPI_USR1_OFFS = 0x1C
|
||||
SPI_USR2_OFFS = 0x20
|
||||
SPI_MOSI_DLEN_OFFS = 0x24
|
||||
SPI_MISO_DLEN_OFFS = 0x28
|
||||
SPI_W0_OFFS = 0x58
|
||||
|
||||
UART_DATE_REG_ADDR = 0x60000000 + 0x7C
|
||||
|
||||
EFUSE_BASE = 0x600B0800
|
||||
EFUSE_BLOCK1_ADDR = EFUSE_BASE + 0x044
|
||||
MAC_EFUSE_REG = EFUSE_BASE + 0x044
|
||||
|
||||
EFUSE_RD_REG_BASE = EFUSE_BASE + 0x030 # BLOCK0 read base address
|
||||
|
||||
EFUSE_PURPOSE_KEY0_REG = EFUSE_BASE + 0x34
|
||||
EFUSE_PURPOSE_KEY0_SHIFT = 24
|
||||
EFUSE_PURPOSE_KEY1_REG = EFUSE_BASE + 0x34
|
||||
EFUSE_PURPOSE_KEY1_SHIFT = 28
|
||||
EFUSE_PURPOSE_KEY2_REG = EFUSE_BASE + 0x38
|
||||
EFUSE_PURPOSE_KEY2_SHIFT = 0
|
||||
EFUSE_PURPOSE_KEY3_REG = EFUSE_BASE + 0x38
|
||||
EFUSE_PURPOSE_KEY3_SHIFT = 4
|
||||
EFUSE_PURPOSE_KEY4_REG = EFUSE_BASE + 0x38
|
||||
EFUSE_PURPOSE_KEY4_SHIFT = 8
|
||||
EFUSE_PURPOSE_KEY5_REG = EFUSE_BASE + 0x38
|
||||
EFUSE_PURPOSE_KEY5_SHIFT = 12
|
||||
|
||||
EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT_REG = EFUSE_RD_REG_BASE
|
||||
EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT = 1 << 20
|
||||
|
||||
EFUSE_SPI_BOOT_CRYPT_CNT_REG = EFUSE_BASE + 0x034
|
||||
EFUSE_SPI_BOOT_CRYPT_CNT_MASK = 0x7 << 18
|
||||
|
||||
EFUSE_SECURE_BOOT_EN_REG = EFUSE_BASE + 0x038
|
||||
EFUSE_SECURE_BOOT_EN_MASK = 1 << 20
|
||||
|
||||
PURPOSE_VAL_XTS_AES128_KEY = 4
|
||||
|
||||
SUPPORTS_ENCRYPTED_FLASH = True
|
||||
|
||||
FLASH_ENCRYPTED_WRITE_ALIGN = 16
|
||||
|
||||
UARTDEV_BUF_NO = 0x4087F580 # Variable in ROM .bss which indicates the port in use
|
||||
UARTDEV_BUF_NO_USB_JTAG_SERIAL = 3 # The above var when USB-JTAG/Serial is used
|
||||
|
||||
DR_REG_LP_WDT_BASE = 0x600B1C00
|
||||
RTC_CNTL_WDTCONFIG0_REG = DR_REG_LP_WDT_BASE + 0x0 # LP_WDT_RWDT_CONFIG0_REG
|
||||
RTC_CNTL_WDTWPROTECT_REG = DR_REG_LP_WDT_BASE + 0x0018 # LP_WDT_RWDT_WPROTECT_REG
|
||||
|
||||
RTC_CNTL_SWD_CONF_REG = DR_REG_LP_WDT_BASE + 0x001C # LP_WDT_SWD_CONFIG_REG
|
||||
RTC_CNTL_SWD_AUTO_FEED_EN = 1 << 18
|
||||
RTC_CNTL_SWD_WPROTECT_REG = DR_REG_LP_WDT_BASE + 0x0020 # LP_WDT_SWD_WPROTECT_REG
|
||||
RTC_CNTL_SWD_WKEY = 0x50D83AA1 # LP_WDT_SWD_WKEY, same as WDT key in this case
|
||||
|
||||
FLASH_FREQUENCY = {
|
||||
"80m": 0x0, # workaround for wrong mspi HS div value in ROM
|
||||
"40m": 0x0,
|
||||
"20m": 0x2,
|
||||
}
|
||||
|
||||
MEMORY_MAP = [
|
||||
[0x00000000, 0x00010000, "PADDING"],
|
||||
[0x42800000, 0x43000000, "DROM"],
|
||||
[0x40800000, 0x40880000, "DRAM"],
|
||||
[0x40800000, 0x40880000, "BYTE_ACCESSIBLE"],
|
||||
[0x4004AC00, 0x40050000, "DROM_MASK"],
|
||||
[0x40000000, 0x4004AC00, "IROM_MASK"],
|
||||
[0x42000000, 0x42800000, "IROM"],
|
||||
[0x40800000, 0x40880000, "IRAM"],
|
||||
[0x50000000, 0x50004000, "RTC_IRAM"],
|
||||
[0x50000000, 0x50004000, "RTC_DRAM"],
|
||||
[0x600FE000, 0x60100000, "MEM_INTERNAL2"],
|
||||
]
|
||||
|
||||
UF2_FAMILY_ID = 0x540DDF62
|
||||
|
||||
def get_pkg_version(self):
|
||||
num_word = 3
|
||||
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 24) & 0x07
|
||||
|
||||
def get_minor_chip_version(self):
|
||||
num_word = 3
|
||||
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 18) & 0x0F
|
||||
|
||||
def get_major_chip_version(self):
|
||||
num_word = 3
|
||||
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 22) & 0x03
|
||||
|
||||
def get_chip_description(self):
|
||||
chip_name = {
|
||||
0: "ESP32-C6 (QFN40)",
|
||||
1: "ESP32-C6FH4 (QFN32)",
|
||||
}.get(self.get_pkg_version(), "unknown ESP32-C6")
|
||||
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_chip_features(self):
|
||||
return ["WiFi 6", "BT 5", "IEEE802.15.4"]
|
||||
|
||||
def get_crystal_freq(self):
|
||||
# ESP32C6 XTAL is fixed to 40MHz
|
||||
return 40
|
||||
|
||||
def override_vddsdio(self, new_voltage):
|
||||
raise NotImplementedInROMError(
|
||||
"VDD_SDIO overrides are not supported for ESP32-C6"
|
||||
)
|
||||
|
||||
def read_mac(self, mac_type="BASE_MAC"):
|
||||
"""Read MAC from EFUSE region"""
|
||||
mac0 = self.read_reg(self.MAC_EFUSE_REG)
|
||||
mac1 = self.read_reg(self.MAC_EFUSE_REG + 4) # only bottom 16 bits are MAC
|
||||
base_mac = struct.pack(">II", mac1, mac0)[2:]
|
||||
ext_mac = struct.pack(">H", (mac1 >> 16) & 0xFFFF)
|
||||
eui64 = base_mac[0:3] + ext_mac + base_mac[3:6]
|
||||
# BASE MAC: 60:55:f9:f7:2c:a2
|
||||
# EUI64 MAC: 60:55:f9:ff:fe:f7:2c:a2
|
||||
# EXT_MAC: ff:fe
|
||||
macs = {
|
||||
"BASE_MAC": tuple(base_mac),
|
||||
"EUI64": tuple(eui64),
|
||||
"MAC_EXT": tuple(ext_mac),
|
||||
}
|
||||
return macs.get(mac_type, None)
|
||||
|
||||
def get_flash_crypt_config(self):
|
||||
return None # doesn't exist on ESP32-C6
|
||||
|
||||
def get_secure_boot_enabled(self):
|
||||
return (
|
||||
self.read_reg(self.EFUSE_SECURE_BOOT_EN_REG)
|
||||
& self.EFUSE_SECURE_BOOT_EN_MASK
|
||||
)
|
||||
|
||||
def get_key_block_purpose(self, key_block):
|
||||
if key_block < 0 or key_block > 5:
|
||||
raise FatalError("Valid key block numbers must be in range 0-5")
|
||||
|
||||
reg, shift = [
|
||||
(self.EFUSE_PURPOSE_KEY0_REG, self.EFUSE_PURPOSE_KEY0_SHIFT),
|
||||
(self.EFUSE_PURPOSE_KEY1_REG, self.EFUSE_PURPOSE_KEY1_SHIFT),
|
||||
(self.EFUSE_PURPOSE_KEY2_REG, self.EFUSE_PURPOSE_KEY2_SHIFT),
|
||||
(self.EFUSE_PURPOSE_KEY3_REG, self.EFUSE_PURPOSE_KEY3_SHIFT),
|
||||
(self.EFUSE_PURPOSE_KEY4_REG, self.EFUSE_PURPOSE_KEY4_SHIFT),
|
||||
(self.EFUSE_PURPOSE_KEY5_REG, self.EFUSE_PURPOSE_KEY5_SHIFT),
|
||||
][key_block]
|
||||
return (self.read_reg(reg) >> shift) & 0xF
|
||||
|
||||
def is_flash_encryption_key_valid(self):
|
||||
# Need to see an AES-128 key
|
||||
purposes = [self.get_key_block_purpose(b) for b in range(6)]
|
||||
|
||||
return any(p == self.PURPOSE_VAL_XTS_AES128_KEY for p in purposes)
|
||||
|
||||
def check_spi_connection(self, spi_connection):
|
||||
if not set(spi_connection).issubset(set(range(0, 31))):
|
||||
raise FatalError("SPI Pin numbers must be in the range 0-30.")
|
||||
if any([v for v in spi_connection if v in [12, 13]]):
|
||||
print(
|
||||
"WARNING: GPIO pins 12 and 13 are used by USB-Serial/JTAG, "
|
||||
"consider using other pins for SPI flash connection."
|
||||
)
|
||||
|
||||
|
||||
class ESP32C6StubLoader(ESP32C6ROM):
|
||||
"""Access class for ESP32C6 stub loader, runs on top of ROM.
|
||||
|
||||
(Basically the same as ESP32StubLoader, but different base class.
|
||||
Can possibly be made into a mixin.)
|
||||
"""
|
||||
|
||||
FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c
|
||||
STATUS_BYTES_LENGTH = 2 # same as ESP8266, different to ESP32 ROM
|
||||
IS_STUB = True
|
||||
|
||||
def __init__(self, rom_loader):
|
||||
self.secure_download_mode = rom_loader.secure_download_mode
|
||||
self._port = rom_loader._port
|
||||
self._trace_enabled = rom_loader._trace_enabled
|
||||
self.cache = rom_loader.cache
|
||||
self.flush_input() # resets _slip_reader
|
||||
|
||||
|
||||
ESP32C6ROM.STUB_CLASS = ESP32C6StubLoader
|
||||
@@ -0,0 +1,27 @@
|
||||
# SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton,
|
||||
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
from .esp32c3 import ESP32C3ROM
|
||||
|
||||
|
||||
class ESP32C6BETAROM(ESP32C3ROM):
|
||||
CHIP_NAME = "ESP32-C6(beta)"
|
||||
IMAGE_CHIP_ID = 7
|
||||
|
||||
CHIP_DETECT_MAGIC_VALUE = [0x0DA1806F]
|
||||
|
||||
UART_DATE_REG_ADDR = 0x00000500
|
||||
|
||||
def get_chip_description(self):
|
||||
chip_name = {
|
||||
0: "ESP32-C6 (QFN40)",
|
||||
1: "ESP32-C6FH4 (QFN32)",
|
||||
}.get(self.get_pkg_version(), "unknown ESP32-C6")
|
||||
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 _post_connect(self):
|
||||
pass
|
||||
@@ -0,0 +1,91 @@
|
||||
# SPDX-FileCopyrightText: 2022 Fredrik Ahlberg, Angus Gratton,
|
||||
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
from .esp32c6 import ESP32C6ROM
|
||||
from ..util import FatalError
|
||||
|
||||
|
||||
class ESP32H2ROM(ESP32C6ROM):
|
||||
CHIP_NAME = "ESP32-H2"
|
||||
IMAGE_CHIP_ID = 16
|
||||
|
||||
# Magic value for ESP32H2
|
||||
CHIP_DETECT_MAGIC_VALUE = [0xD7B73E80]
|
||||
|
||||
DR_REG_LP_WDT_BASE = 0x600B1C00
|
||||
RTC_CNTL_WDTCONFIG0_REG = DR_REG_LP_WDT_BASE + 0x0 # LP_WDT_RWDT_CONFIG0_REG
|
||||
RTC_CNTL_WDTWPROTECT_REG = DR_REG_LP_WDT_BASE + 0x001C # LP_WDT_RWDT_WPROTECT_REG
|
||||
|
||||
RTC_CNTL_SWD_CONF_REG = DR_REG_LP_WDT_BASE + 0x0020 # LP_WDT_SWD_CONFIG_REG
|
||||
RTC_CNTL_SWD_AUTO_FEED_EN = 1 << 18
|
||||
RTC_CNTL_SWD_WPROTECT_REG = DR_REG_LP_WDT_BASE + 0x0024 # LP_WDT_SWD_WPROTECT_REG
|
||||
RTC_CNTL_SWD_WKEY = 0x50D83AA1 # LP_WDT_SWD_WKEY, same as WDT key in this case
|
||||
|
||||
FLASH_FREQUENCY = {
|
||||
"48m": 0xF,
|
||||
"24m": 0x0,
|
||||
"16m": 0x1,
|
||||
"12m": 0x2,
|
||||
}
|
||||
|
||||
UF2_FAMILY_ID = 0x332726F6
|
||||
|
||||
def get_pkg_version(self):
|
||||
num_word = 4
|
||||
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 0) & 0x07
|
||||
|
||||
def get_minor_chip_version(self):
|
||||
num_word = 3
|
||||
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 18) & 0x07
|
||||
|
||||
def get_major_chip_version(self):
|
||||
num_word = 3
|
||||
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 21) & 0x03
|
||||
|
||||
def get_chip_description(self):
|
||||
chip_name = {
|
||||
0: "ESP32-H2",
|
||||
}.get(self.get_pkg_version(), "unknown ESP32-H2")
|
||||
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_chip_features(self):
|
||||
return ["BLE", "IEEE802.15.4"]
|
||||
|
||||
def get_crystal_freq(self):
|
||||
# ESP32H2 XTAL is fixed to 32MHz
|
||||
return 32
|
||||
|
||||
def check_spi_connection(self, spi_connection):
|
||||
if not set(spi_connection).issubset(set(range(0, 28))):
|
||||
raise FatalError("SPI Pin numbers must be in the range 0-27.")
|
||||
if any([v for v in spi_connection if v in [26, 27]]):
|
||||
print(
|
||||
"WARNING: GPIO pins 26 and 27 are used by USB-Serial/JTAG, "
|
||||
"consider using other pins for SPI flash connection."
|
||||
)
|
||||
|
||||
|
||||
class ESP32H2StubLoader(ESP32H2ROM):
|
||||
"""Access class for ESP32H2 stub loader, runs on top of ROM.
|
||||
|
||||
(Basically the same as ESP32StubLoader, but different base class.
|
||||
Can possibly be made into a mixin.)
|
||||
"""
|
||||
|
||||
FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c
|
||||
STATUS_BYTES_LENGTH = 2 # same as ESP8266, different to ESP32 ROM
|
||||
IS_STUB = True
|
||||
|
||||
def __init__(self, rom_loader):
|
||||
self.secure_download_mode = rom_loader.secure_download_mode
|
||||
self._port = rom_loader._port
|
||||
self._trace_enabled = rom_loader._trace_enabled
|
||||
self.cache = rom_loader.cache
|
||||
self.flush_input() # resets _slip_reader
|
||||
|
||||
|
||||
ESP32H2ROM.STUB_CLASS = ESP32H2StubLoader
|
||||
@@ -0,0 +1,164 @@
|
||||
# SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton,
|
||||
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
import struct
|
||||
|
||||
from .esp32c3 import ESP32C3ROM
|
||||
from ..util import FatalError, NotImplementedInROMError
|
||||
|
||||
|
||||
class ESP32H2BETA1ROM(ESP32C3ROM):
|
||||
CHIP_NAME = "ESP32-H2(beta1)"
|
||||
IMAGE_CHIP_ID = 10
|
||||
|
||||
IROM_MAP_START = 0x42000000
|
||||
IROM_MAP_END = 0x42800000
|
||||
DROM_MAP_START = 0x3C000000
|
||||
DROM_MAP_END = 0x3C800000
|
||||
|
||||
SPI_REG_BASE = 0x60002000
|
||||
SPI_USR_OFFS = 0x18
|
||||
SPI_USR1_OFFS = 0x1C
|
||||
SPI_USR2_OFFS = 0x20
|
||||
SPI_MOSI_DLEN_OFFS = 0x24
|
||||
SPI_MISO_DLEN_OFFS = 0x28
|
||||
SPI_W0_OFFS = 0x58
|
||||
|
||||
BOOTLOADER_FLASH_OFFSET = 0x0
|
||||
|
||||
CHIP_DETECT_MAGIC_VALUE = [0xCA26CC22]
|
||||
|
||||
UART_DATE_REG_ADDR = 0x60000000 + 0x7C
|
||||
|
||||
EFUSE_BASE = 0x6001A000
|
||||
EFUSE_BLOCK1_ADDR = EFUSE_BASE + 0x044
|
||||
MAC_EFUSE_REG = EFUSE_BASE + 0x044
|
||||
|
||||
EFUSE_RD_REG_BASE = EFUSE_BASE + 0x030 # BLOCK0 read base address
|
||||
|
||||
EFUSE_PURPOSE_KEY0_REG = EFUSE_BASE + 0x34
|
||||
EFUSE_PURPOSE_KEY0_SHIFT = 24
|
||||
EFUSE_PURPOSE_KEY1_REG = EFUSE_BASE + 0x34
|
||||
EFUSE_PURPOSE_KEY1_SHIFT = 28
|
||||
EFUSE_PURPOSE_KEY2_REG = EFUSE_BASE + 0x38
|
||||
EFUSE_PURPOSE_KEY2_SHIFT = 0
|
||||
EFUSE_PURPOSE_KEY3_REG = EFUSE_BASE + 0x38
|
||||
EFUSE_PURPOSE_KEY3_SHIFT = 4
|
||||
EFUSE_PURPOSE_KEY4_REG = EFUSE_BASE + 0x38
|
||||
EFUSE_PURPOSE_KEY4_SHIFT = 8
|
||||
EFUSE_PURPOSE_KEY5_REG = EFUSE_BASE + 0x38
|
||||
EFUSE_PURPOSE_KEY5_SHIFT = 12
|
||||
|
||||
EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT_REG = EFUSE_RD_REG_BASE
|
||||
EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT = 1 << 20
|
||||
|
||||
EFUSE_SPI_BOOT_CRYPT_CNT_REG = EFUSE_BASE + 0x034
|
||||
EFUSE_SPI_BOOT_CRYPT_CNT_MASK = 0x7 << 18
|
||||
|
||||
EFUSE_SECURE_BOOT_EN_REG = EFUSE_BASE + 0x038
|
||||
EFUSE_SECURE_BOOT_EN_MASK = 1 << 20
|
||||
|
||||
PURPOSE_VAL_XTS_AES128_KEY = 4
|
||||
|
||||
SUPPORTS_ENCRYPTED_FLASH = True
|
||||
|
||||
FLASH_ENCRYPTED_WRITE_ALIGN = 16
|
||||
|
||||
MEMORY_MAP = []
|
||||
|
||||
FLASH_FREQUENCY = {
|
||||
"48m": 0xF,
|
||||
"24m": 0x0,
|
||||
"16m": 0x1,
|
||||
"12m": 0x2,
|
||||
}
|
||||
|
||||
def get_pkg_version(self):
|
||||
num_word = 4
|
||||
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 0) & 0x07
|
||||
|
||||
def get_minor_chip_version(self):
|
||||
num_word = 3
|
||||
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 18) & 0x07
|
||||
|
||||
def get_major_chip_version(self):
|
||||
num_word = 3
|
||||
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 21) & 0x03
|
||||
|
||||
def get_chip_description(self):
|
||||
chip_name = {
|
||||
0: "ESP32-H2",
|
||||
}.get(self.get_pkg_version(), "unknown ESP32-H2")
|
||||
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_chip_features(self):
|
||||
return ["BLE", "IEEE802.15.4"]
|
||||
|
||||
def get_crystal_freq(self):
|
||||
return 32
|
||||
|
||||
def override_vddsdio(self, new_voltage):
|
||||
raise NotImplementedInROMError(
|
||||
"VDD_SDIO overrides are not supported for ESP32-H2"
|
||||
)
|
||||
|
||||
def read_mac(self, mac_type="BASE_MAC"):
|
||||
"""Read MAC from EFUSE region"""
|
||||
if mac_type != "BASE_MAC":
|
||||
return None
|
||||
mac0 = self.read_reg(self.MAC_EFUSE_REG)
|
||||
mac1 = self.read_reg(self.MAC_EFUSE_REG + 4) # only bottom 16 bits are MAC
|
||||
bitstring = struct.pack(">II", mac1, mac0)[2:]
|
||||
return tuple(bitstring)
|
||||
|
||||
def get_flash_crypt_config(self):
|
||||
return None # doesn't exist on ESP32-H2
|
||||
|
||||
def get_key_block_purpose(self, key_block):
|
||||
if key_block < 0 or key_block > 5:
|
||||
raise FatalError("Valid key block numbers must be in range 0-5")
|
||||
|
||||
reg, shift = [
|
||||
(self.EFUSE_PURPOSE_KEY0_REG, self.EFUSE_PURPOSE_KEY0_SHIFT),
|
||||
(self.EFUSE_PURPOSE_KEY1_REG, self.EFUSE_PURPOSE_KEY1_SHIFT),
|
||||
(self.EFUSE_PURPOSE_KEY2_REG, self.EFUSE_PURPOSE_KEY2_SHIFT),
|
||||
(self.EFUSE_PURPOSE_KEY3_REG, self.EFUSE_PURPOSE_KEY3_SHIFT),
|
||||
(self.EFUSE_PURPOSE_KEY4_REG, self.EFUSE_PURPOSE_KEY4_SHIFT),
|
||||
(self.EFUSE_PURPOSE_KEY5_REG, self.EFUSE_PURPOSE_KEY5_SHIFT),
|
||||
][key_block]
|
||||
return (self.read_reg(reg) >> shift) & 0xF
|
||||
|
||||
def is_flash_encryption_key_valid(self):
|
||||
# Need to see an AES-128 key
|
||||
purposes = [self.get_key_block_purpose(b) for b in range(6)]
|
||||
|
||||
return any(p == self.PURPOSE_VAL_XTS_AES128_KEY for p in purposes)
|
||||
|
||||
def _post_connect(self):
|
||||
pass
|
||||
|
||||
|
||||
class ESP32H2BETA1StubLoader(ESP32H2BETA1ROM):
|
||||
"""Access class for ESP32H2BETA1 stub loader, runs on top of ROM.
|
||||
|
||||
(Basically the same as ESP32StubLoader, but different base class.
|
||||
Can possibly be made into a mixin.)
|
||||
"""
|
||||
|
||||
FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c
|
||||
STATUS_BYTES_LENGTH = 2 # same as ESP8266, different to ESP32 ROM
|
||||
IS_STUB = True
|
||||
|
||||
def __init__(self, rom_loader):
|
||||
self.secure_download_mode = rom_loader.secure_download_mode
|
||||
self._port = rom_loader._port
|
||||
self._trace_enabled = rom_loader._trace_enabled
|
||||
self.cache = rom_loader.cache
|
||||
self.flush_input() # resets _slip_reader
|
||||
|
||||
|
||||
ESP32H2BETA1ROM.STUB_CLASS = ESP32H2BETA1StubLoader
|
||||
@@ -0,0 +1,43 @@
|
||||
# SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton,
|
||||
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
from .esp32h2beta1 import ESP32H2BETA1ROM
|
||||
|
||||
|
||||
class ESP32H2BETA2ROM(ESP32H2BETA1ROM):
|
||||
CHIP_NAME = "ESP32-H2(beta2)"
|
||||
IMAGE_CHIP_ID = 14
|
||||
|
||||
CHIP_DETECT_MAGIC_VALUE = [0x6881B06F]
|
||||
|
||||
def get_chip_description(self):
|
||||
chip_name = {
|
||||
1: "ESP32-H2(beta2)",
|
||||
}.get(self.get_pkg_version(), "unknown ESP32-H2")
|
||||
major_rev = self.get_major_chip_version()
|
||||
minor_rev = self.get_minor_chip_version()
|
||||
return f"{chip_name} (revision v{major_rev}.{minor_rev})"
|
||||
|
||||
|
||||
class ESP32H2BETA2StubLoader(ESP32H2BETA2ROM):
|
||||
"""Access class for ESP32H2BETA2 stub loader, runs on top of ROM.
|
||||
|
||||
(Basically the same as ESP32StubLoader, but different base class.
|
||||
Can possibly be made into a mixin.)
|
||||
"""
|
||||
|
||||
FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c
|
||||
STATUS_BYTES_LENGTH = 2 # same as ESP8266, different to ESP32 ROM
|
||||
IS_STUB = True
|
||||
|
||||
def __init__(self, rom_loader):
|
||||
self.secure_download_mode = rom_loader.secure_download_mode
|
||||
self._port = rom_loader._port
|
||||
self._trace_enabled = rom_loader._trace_enabled
|
||||
self.cache = rom_loader.cache
|
||||
self.flush_input() # resets _slip_reader
|
||||
|
||||
|
||||
ESP32H2BETA2ROM.STUB_CLASS = ESP32H2BETA2StubLoader
|
||||
@@ -0,0 +1,195 @@
|
||||
# SPDX-FileCopyrightText: 2023 Fredrik Ahlberg, Angus Gratton,
|
||||
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
import struct
|
||||
|
||||
from .esp32 import ESP32ROM
|
||||
from ..loader import ESPLoader
|
||||
from ..util import FatalError, NotImplementedInROMError
|
||||
|
||||
|
||||
class ESP32P4ROM(ESP32ROM):
|
||||
CHIP_NAME = "ESP32-P4"
|
||||
IMAGE_CHIP_ID = 18
|
||||
|
||||
IROM_MAP_START = 0x40000000
|
||||
IROM_MAP_END = 0x4C000000
|
||||
DROM_MAP_START = 0x40000000
|
||||
DROM_MAP_END = 0x4C000000
|
||||
|
||||
BOOTLOADER_FLASH_OFFSET = 0x2000 # First 2 sectors are reserved for FE purposes
|
||||
|
||||
CHIP_DETECT_MAGIC_VALUE = [0x0]
|
||||
|
||||
UART_DATE_REG_ADDR = 0x500CA000 + 0x8C
|
||||
|
||||
EFUSE_BASE = 0x5012D000
|
||||
EFUSE_BLOCK1_ADDR = EFUSE_BASE + 0x044
|
||||
MAC_EFUSE_REG = EFUSE_BASE + 0x044
|
||||
|
||||
SPI_REG_BASE = 0x5008D000 # SPIMEM1
|
||||
SPI_USR_OFFS = 0x18
|
||||
SPI_USR1_OFFS = 0x1C
|
||||
SPI_USR2_OFFS = 0x20
|
||||
SPI_MOSI_DLEN_OFFS = 0x24
|
||||
SPI_MISO_DLEN_OFFS = 0x28
|
||||
SPI_W0_OFFS = 0x58
|
||||
|
||||
EFUSE_RD_REG_BASE = EFUSE_BASE + 0x030 # BLOCK0 read base address
|
||||
|
||||
EFUSE_PURPOSE_KEY0_REG = EFUSE_BASE + 0x34
|
||||
EFUSE_PURPOSE_KEY0_SHIFT = 24
|
||||
EFUSE_PURPOSE_KEY1_REG = EFUSE_BASE + 0x34
|
||||
EFUSE_PURPOSE_KEY1_SHIFT = 28
|
||||
EFUSE_PURPOSE_KEY2_REG = EFUSE_BASE + 0x38
|
||||
EFUSE_PURPOSE_KEY2_SHIFT = 0
|
||||
EFUSE_PURPOSE_KEY3_REG = EFUSE_BASE + 0x38
|
||||
EFUSE_PURPOSE_KEY3_SHIFT = 4
|
||||
EFUSE_PURPOSE_KEY4_REG = EFUSE_BASE + 0x38
|
||||
EFUSE_PURPOSE_KEY4_SHIFT = 8
|
||||
EFUSE_PURPOSE_KEY5_REG = EFUSE_BASE + 0x38
|
||||
EFUSE_PURPOSE_KEY5_SHIFT = 12
|
||||
|
||||
EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT_REG = EFUSE_RD_REG_BASE
|
||||
EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT = 1 << 20
|
||||
|
||||
EFUSE_SPI_BOOT_CRYPT_CNT_REG = EFUSE_BASE + 0x034
|
||||
EFUSE_SPI_BOOT_CRYPT_CNT_MASK = 0x7 << 18
|
||||
|
||||
EFUSE_SECURE_BOOT_EN_REG = EFUSE_BASE + 0x038
|
||||
EFUSE_SECURE_BOOT_EN_MASK = 1 << 20
|
||||
|
||||
PURPOSE_VAL_XTS_AES256_KEY_1 = 2
|
||||
PURPOSE_VAL_XTS_AES256_KEY_2 = 3
|
||||
PURPOSE_VAL_XTS_AES128_KEY = 4
|
||||
|
||||
SUPPORTS_ENCRYPTED_FLASH = True
|
||||
|
||||
FLASH_ENCRYPTED_WRITE_ALIGN = 16
|
||||
|
||||
MEMORY_MAP = [
|
||||
[0x00000000, 0x00010000, "PADDING"],
|
||||
[0x40000000, 0x4C000000, "DROM"],
|
||||
[0x4FF00000, 0x4FFA0000, "DRAM"],
|
||||
[0x4FF00000, 0x4FFA0000, "BYTE_ACCESSIBLE"],
|
||||
[0x4FC00000, 0x4FC20000, "DROM_MASK"],
|
||||
[0x4FC00000, 0x4FC20000, "IROM_MASK"],
|
||||
[0x40000000, 0x4C000000, "IROM"],
|
||||
[0x4FF00000, 0x4FFA0000, "IRAM"],
|
||||
[0x50108000, 0x50110000, "RTC_IRAM"],
|
||||
[0x50108000, 0x50110000, "RTC_DRAM"],
|
||||
[0x600FE000, 0x60100000, "MEM_INTERNAL2"],
|
||||
]
|
||||
|
||||
UF2_FAMILY_ID = 0x3D308E94
|
||||
|
||||
def get_pkg_version(self):
|
||||
# ESP32P4 TODO
|
||||
return 0
|
||||
|
||||
def get_minor_chip_version(self):
|
||||
# ESP32P4 TODO
|
||||
return 0
|
||||
|
||||
def get_major_chip_version(self):
|
||||
# ESP32P4 TODO
|
||||
return 0
|
||||
|
||||
def get_chip_description(self):
|
||||
chip_name = {
|
||||
0: "ESP32-P4",
|
||||
}.get(self.get_pkg_version(), "unknown ESP32-P4")
|
||||
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_chip_features(self):
|
||||
return ["High-Performance MCU"]
|
||||
|
||||
def get_crystal_freq(self):
|
||||
# ESP32P4 XTAL is fixed to 40MHz
|
||||
return 40
|
||||
|
||||
def override_vddsdio(self, new_voltage):
|
||||
raise NotImplementedInROMError(
|
||||
"VDD_SDIO overrides are not supported for ESP32-P4"
|
||||
)
|
||||
|
||||
def read_mac(self, mac_type="BASE_MAC"):
|
||||
"""Read MAC from EFUSE region"""
|
||||
if mac_type != "BASE_MAC":
|
||||
return None
|
||||
mac0 = self.read_reg(self.MAC_EFUSE_REG)
|
||||
mac1 = self.read_reg(self.MAC_EFUSE_REG + 4) # only bottom 16 bits are MAC
|
||||
bitstring = struct.pack(">II", mac1, mac0)[2:]
|
||||
return tuple(bitstring)
|
||||
|
||||
def get_flash_crypt_config(self):
|
||||
return None # doesn't exist on ESP32-P4
|
||||
|
||||
def get_secure_boot_enabled(self):
|
||||
return (
|
||||
self.read_reg(self.EFUSE_SECURE_BOOT_EN_REG)
|
||||
& self.EFUSE_SECURE_BOOT_EN_MASK
|
||||
)
|
||||
|
||||
def get_key_block_purpose(self, key_block):
|
||||
if key_block < 0 or key_block > 5:
|
||||
raise FatalError("Valid key block numbers must be in range 0-5")
|
||||
|
||||
reg, shift = [
|
||||
(self.EFUSE_PURPOSE_KEY0_REG, self.EFUSE_PURPOSE_KEY0_SHIFT),
|
||||
(self.EFUSE_PURPOSE_KEY1_REG, self.EFUSE_PURPOSE_KEY1_SHIFT),
|
||||
(self.EFUSE_PURPOSE_KEY2_REG, self.EFUSE_PURPOSE_KEY2_SHIFT),
|
||||
(self.EFUSE_PURPOSE_KEY3_REG, self.EFUSE_PURPOSE_KEY3_SHIFT),
|
||||
(self.EFUSE_PURPOSE_KEY4_REG, self.EFUSE_PURPOSE_KEY4_SHIFT),
|
||||
(self.EFUSE_PURPOSE_KEY5_REG, self.EFUSE_PURPOSE_KEY5_SHIFT),
|
||||
][key_block]
|
||||
return (self.read_reg(reg) >> shift) & 0xF
|
||||
|
||||
def is_flash_encryption_key_valid(self):
|
||||
# Need to see either an AES-128 key or two AES-256 keys
|
||||
purposes = [self.get_key_block_purpose(b) for b in range(6)]
|
||||
|
||||
if any(p == self.PURPOSE_VAL_XTS_AES128_KEY for p in purposes):
|
||||
return True
|
||||
|
||||
return any(p == self.PURPOSE_VAL_XTS_AES256_KEY_1 for p in purposes) and any(
|
||||
p == self.PURPOSE_VAL_XTS_AES256_KEY_2 for p in purposes
|
||||
)
|
||||
|
||||
def change_baud(self, baud):
|
||||
ESPLoader.change_baud(self, baud)
|
||||
|
||||
def _post_connect(self):
|
||||
pass
|
||||
# TODO: Disable watchdogs when USB modes are supported in the stub
|
||||
# if not self.sync_stub_detected: # Don't run if stub is reused
|
||||
# self.disable_watchdogs()
|
||||
|
||||
def check_spi_connection(self, spi_connection):
|
||||
pass # TODO: Define GPIOs for --spi-connection
|
||||
|
||||
|
||||
class ESP32P4StubLoader(ESP32P4ROM):
|
||||
"""Access class for ESP32P4 stub loader, runs on top of ROM.
|
||||
|
||||
(Basically the same as ESP32StubLoader, but different base class.
|
||||
Can possibly be made into a mixin.)
|
||||
"""
|
||||
|
||||
FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c
|
||||
STATUS_BYTES_LENGTH = 2 # same as ESP8266, different to ESP32 ROM
|
||||
IS_STUB = True
|
||||
|
||||
def __init__(self, rom_loader):
|
||||
self.secure_download_mode = rom_loader.secure_download_mode
|
||||
self._port = rom_loader._port
|
||||
self._trace_enabled = rom_loader._trace_enabled
|
||||
self.cache = rom_loader.cache
|
||||
self.flush_input() # resets _slip_reader
|
||||
|
||||
|
||||
ESP32P4ROM.STUB_CLASS = ESP32P4StubLoader
|
||||
@@ -0,0 +1,323 @@
|
||||
# SPDX-FileCopyrightText: 2014-2023 Fredrik Ahlberg, Angus Gratton,
|
||||
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
import os
|
||||
import struct
|
||||
|
||||
from .esp32 import ESP32ROM
|
||||
from ..loader import ESPLoader
|
||||
from ..reset import HardReset
|
||||
from ..util import FatalError, NotImplementedInROMError
|
||||
|
||||
|
||||
class ESP32S2ROM(ESP32ROM):
|
||||
CHIP_NAME = "ESP32-S2"
|
||||
IMAGE_CHIP_ID = 2
|
||||
|
||||
IROM_MAP_START = 0x40080000
|
||||
IROM_MAP_END = 0x40B80000
|
||||
DROM_MAP_START = 0x3F000000
|
||||
DROM_MAP_END = 0x3F3F0000
|
||||
|
||||
CHIP_DETECT_MAGIC_VALUE = [0x000007C6]
|
||||
|
||||
SPI_REG_BASE = 0x3F402000
|
||||
SPI_USR_OFFS = 0x18
|
||||
SPI_USR1_OFFS = 0x1C
|
||||
SPI_USR2_OFFS = 0x20
|
||||
SPI_MOSI_DLEN_OFFS = 0x24
|
||||
SPI_MISO_DLEN_OFFS = 0x28
|
||||
SPI_W0_OFFS = 0x58
|
||||
|
||||
MAC_EFUSE_REG = 0x3F41A044 # ESP32-S2 has special block for MAC efuses
|
||||
|
||||
UART_CLKDIV_REG = 0x3F400014
|
||||
|
||||
SUPPORTS_ENCRYPTED_FLASH = True
|
||||
|
||||
FLASH_ENCRYPTED_WRITE_ALIGN = 16
|
||||
|
||||
# todo: use espefuse APIs to get this info
|
||||
EFUSE_BASE = 0x3F41A000
|
||||
EFUSE_RD_REG_BASE = EFUSE_BASE + 0x030 # BLOCK0 read base address
|
||||
EFUSE_BLOCK1_ADDR = EFUSE_BASE + 0x044
|
||||
EFUSE_BLOCK2_ADDR = EFUSE_BASE + 0x05C
|
||||
|
||||
EFUSE_PURPOSE_KEY0_REG = EFUSE_BASE + 0x34
|
||||
EFUSE_PURPOSE_KEY0_SHIFT = 24
|
||||
EFUSE_PURPOSE_KEY1_REG = EFUSE_BASE + 0x34
|
||||
EFUSE_PURPOSE_KEY1_SHIFT = 28
|
||||
EFUSE_PURPOSE_KEY2_REG = EFUSE_BASE + 0x38
|
||||
EFUSE_PURPOSE_KEY2_SHIFT = 0
|
||||
EFUSE_PURPOSE_KEY3_REG = EFUSE_BASE + 0x38
|
||||
EFUSE_PURPOSE_KEY3_SHIFT = 4
|
||||
EFUSE_PURPOSE_KEY4_REG = EFUSE_BASE + 0x38
|
||||
EFUSE_PURPOSE_KEY4_SHIFT = 8
|
||||
EFUSE_PURPOSE_KEY5_REG = EFUSE_BASE + 0x38
|
||||
EFUSE_PURPOSE_KEY5_SHIFT = 12
|
||||
|
||||
EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT_REG = EFUSE_RD_REG_BASE
|
||||
EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT = 1 << 19
|
||||
|
||||
EFUSE_SPI_BOOT_CRYPT_CNT_REG = EFUSE_BASE + 0x034
|
||||
EFUSE_SPI_BOOT_CRYPT_CNT_MASK = 0x7 << 18
|
||||
|
||||
EFUSE_SECURE_BOOT_EN_REG = EFUSE_BASE + 0x038
|
||||
EFUSE_SECURE_BOOT_EN_MASK = 1 << 20
|
||||
|
||||
EFUSE_RD_REPEAT_DATA3_REG = EFUSE_BASE + 0x3C
|
||||
EFUSE_RD_REPEAT_DATA3_REG_FLASH_TYPE_MASK = 1 << 9
|
||||
|
||||
PURPOSE_VAL_XTS_AES256_KEY_1 = 2
|
||||
PURPOSE_VAL_XTS_AES256_KEY_2 = 3
|
||||
PURPOSE_VAL_XTS_AES128_KEY = 4
|
||||
|
||||
UARTDEV_BUF_NO = 0x3FFFFD14 # Variable in ROM .bss which indicates the port in use
|
||||
UARTDEV_BUF_NO_USB_OTG = 2 # Value of the above indicating that USB-OTG is in use
|
||||
|
||||
USB_RAM_BLOCK = 0x800 # Max block size USB-OTG is used
|
||||
|
||||
GPIO_STRAP_REG = 0x3F404038
|
||||
GPIO_STRAP_SPI_BOOT_MASK = 0x8 # Not download mode
|
||||
RTC_CNTL_OPTION1_REG = 0x3F408128
|
||||
RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK = 0x1 # Is download mode forced over USB?
|
||||
|
||||
MEMORY_MAP = [
|
||||
[0x00000000, 0x00010000, "PADDING"],
|
||||
[0x3F000000, 0x3FF80000, "DROM"],
|
||||
[0x3F500000, 0x3FF80000, "EXTRAM_DATA"],
|
||||
[0x3FF9E000, 0x3FFA0000, "RTC_DRAM"],
|
||||
[0x3FF9E000, 0x40000000, "BYTE_ACCESSIBLE"],
|
||||
[0x3FF9E000, 0x40072000, "MEM_INTERNAL"],
|
||||
[0x3FFB0000, 0x40000000, "DRAM"],
|
||||
[0x40000000, 0x4001A100, "IROM_MASK"],
|
||||
[0x40020000, 0x40070000, "IRAM"],
|
||||
[0x40070000, 0x40072000, "RTC_IRAM"],
|
||||
[0x40080000, 0x40800000, "IROM"],
|
||||
[0x50000000, 0x50002000, "RTC_DATA"],
|
||||
]
|
||||
|
||||
UF2_FAMILY_ID = 0xBFDD4EEE
|
||||
|
||||
def get_pkg_version(self):
|
||||
num_word = 4
|
||||
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 0) & 0x0F
|
||||
|
||||
def get_minor_chip_version(self):
|
||||
hi_num_word = 3
|
||||
hi = (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * hi_num_word)) >> 20) & 0x01
|
||||
low_num_word = 4
|
||||
low = (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * low_num_word)) >> 4) & 0x07
|
||||
return (hi << 3) + low
|
||||
|
||||
def get_major_chip_version(self):
|
||||
num_word = 3
|
||||
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 18) & 0x03
|
||||
|
||||
def get_flash_version(self):
|
||||
num_word = 3
|
||||
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 21) & 0x0F
|
||||
|
||||
def get_flash_cap(self):
|
||||
return self.get_flash_version()
|
||||
|
||||
def get_psram_version(self):
|
||||
num_word = 3
|
||||
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 28) & 0x0F
|
||||
|
||||
def get_psram_cap(self):
|
||||
return self.get_psram_version()
|
||||
|
||||
def get_block2_version(self):
|
||||
# BLK_VERSION_MINOR
|
||||
num_word = 4
|
||||
return (self.read_reg(self.EFUSE_BLOCK2_ADDR + (4 * num_word)) >> 4) & 0x07
|
||||
|
||||
def get_chip_description(self):
|
||||
chip_name = {
|
||||
0: "ESP32-S2",
|
||||
1: "ESP32-S2FH2",
|
||||
2: "ESP32-S2FH4",
|
||||
102: "ESP32-S2FNR2",
|
||||
100: "ESP32-S2R2",
|
||||
}.get(
|
||||
self.get_flash_cap() + self.get_psram_cap() * 100,
|
||||
"unknown ESP32-S2",
|
||||
)
|
||||
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_chip_features(self):
|
||||
features = ["WiFi"]
|
||||
|
||||
if self.secure_download_mode:
|
||||
features += ["Secure Download Mode Enabled"]
|
||||
|
||||
flash_version = {
|
||||
0: "No Embedded Flash",
|
||||
1: "Embedded Flash 2MB",
|
||||
2: "Embedded Flash 4MB",
|
||||
}.get(self.get_flash_cap(), "Unknown Embedded Flash")
|
||||
features += [flash_version]
|
||||
|
||||
psram_version = {
|
||||
0: "No Embedded PSRAM",
|
||||
1: "Embedded PSRAM 2MB",
|
||||
2: "Embedded PSRAM 4MB",
|
||||
}.get(self.get_psram_cap(), "Unknown Embedded PSRAM")
|
||||
features += [psram_version]
|
||||
|
||||
block2_version = {
|
||||
0: "No calibration in BLK2 of efuse",
|
||||
1: "ADC and temperature sensor calibration in BLK2 of efuse V1",
|
||||
2: "ADC and temperature sensor calibration in BLK2 of efuse V2",
|
||||
}.get(self.get_block2_version(), "Unknown Calibration in BLK2")
|
||||
features += [block2_version]
|
||||
|
||||
return features
|
||||
|
||||
def get_crystal_freq(self):
|
||||
# ESP32-S2 XTAL is fixed to 40MHz
|
||||
return 40
|
||||
|
||||
def override_vddsdio(self, new_voltage):
|
||||
raise NotImplementedInROMError(
|
||||
"VDD_SDIO overrides are not supported for ESP32-S2"
|
||||
)
|
||||
|
||||
def read_mac(self, mac_type="BASE_MAC"):
|
||||
"""Read MAC from EFUSE region"""
|
||||
if mac_type != "BASE_MAC":
|
||||
return None
|
||||
mac0 = self.read_reg(self.MAC_EFUSE_REG)
|
||||
mac1 = self.read_reg(self.MAC_EFUSE_REG + 4) # only bottom 16 bits are MAC
|
||||
bitstring = struct.pack(">II", mac1, mac0)[2:]
|
||||
return tuple(bitstring)
|
||||
|
||||
def flash_type(self):
|
||||
return (
|
||||
1
|
||||
if self.read_reg(self.EFUSE_RD_REPEAT_DATA3_REG)
|
||||
& self.EFUSE_RD_REPEAT_DATA3_REG_FLASH_TYPE_MASK
|
||||
else 0
|
||||
)
|
||||
|
||||
def get_flash_crypt_config(self):
|
||||
return None # doesn't exist on ESP32-S2
|
||||
|
||||
def get_secure_boot_enabled(self):
|
||||
return (
|
||||
self.read_reg(self.EFUSE_SECURE_BOOT_EN_REG)
|
||||
& self.EFUSE_SECURE_BOOT_EN_MASK
|
||||
)
|
||||
|
||||
def get_key_block_purpose(self, key_block):
|
||||
if key_block < 0 or key_block > 5:
|
||||
raise FatalError("Valid key block numbers must be in range 0-5")
|
||||
|
||||
reg, shift = [
|
||||
(self.EFUSE_PURPOSE_KEY0_REG, self.EFUSE_PURPOSE_KEY0_SHIFT),
|
||||
(self.EFUSE_PURPOSE_KEY1_REG, self.EFUSE_PURPOSE_KEY1_SHIFT),
|
||||
(self.EFUSE_PURPOSE_KEY2_REG, self.EFUSE_PURPOSE_KEY2_SHIFT),
|
||||
(self.EFUSE_PURPOSE_KEY3_REG, self.EFUSE_PURPOSE_KEY3_SHIFT),
|
||||
(self.EFUSE_PURPOSE_KEY4_REG, self.EFUSE_PURPOSE_KEY4_SHIFT),
|
||||
(self.EFUSE_PURPOSE_KEY5_REG, self.EFUSE_PURPOSE_KEY5_SHIFT),
|
||||
][key_block]
|
||||
return (self.read_reg(reg) >> shift) & 0xF
|
||||
|
||||
def is_flash_encryption_key_valid(self):
|
||||
# Need to see either an AES-128 key or two AES-256 keys
|
||||
purposes = [self.get_key_block_purpose(b) for b in range(6)]
|
||||
|
||||
if any(p == self.PURPOSE_VAL_XTS_AES128_KEY for p in purposes):
|
||||
return True
|
||||
|
||||
return any(p == self.PURPOSE_VAL_XTS_AES256_KEY_1 for p in purposes) and any(
|
||||
p == self.PURPOSE_VAL_XTS_AES256_KEY_2 for p in purposes
|
||||
)
|
||||
|
||||
def uses_usb_otg(self):
|
||||
"""
|
||||
Check the UARTDEV_BUF_NO register to see if USB-OTG console is being used
|
||||
"""
|
||||
if self.secure_download_mode:
|
||||
return False # can't detect native USB in secure download mode
|
||||
return self.get_uart_no() == self.UARTDEV_BUF_NO_USB_OTG
|
||||
|
||||
def _post_connect(self):
|
||||
if self.uses_usb_otg():
|
||||
self.ESP_RAM_BLOCK = self.USB_RAM_BLOCK
|
||||
|
||||
def _check_if_can_reset(self):
|
||||
"""
|
||||
Check the strapping register to see if we can reset out of download mode.
|
||||
"""
|
||||
if os.getenv("ESPTOOL_TESTING") is not None:
|
||||
print("ESPTOOL_TESTING is set, ignoring strapping mode check")
|
||||
# Esptool tests over USB-OTG run with GPIO0 strapped low,
|
||||
# don't complain in this case.
|
||||
return
|
||||
strap_reg = self.read_reg(self.GPIO_STRAP_REG)
|
||||
force_dl_reg = self.read_reg(self.RTC_CNTL_OPTION1_REG)
|
||||
if (
|
||||
strap_reg & self.GPIO_STRAP_SPI_BOOT_MASK == 0
|
||||
and force_dl_reg & self.RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK == 0
|
||||
):
|
||||
print(
|
||||
"WARNING: {} chip was placed into download mode using GPIO0.\n"
|
||||
"esptool.py can not exit the download mode over USB. "
|
||||
"To run the app, reset the chip manually.\n"
|
||||
"To suppress this note, set --after option to 'no_reset'.".format(
|
||||
self.get_chip_description()
|
||||
)
|
||||
)
|
||||
raise SystemExit(1)
|
||||
|
||||
def hard_reset(self):
|
||||
uses_usb_otg = self.uses_usb_otg()
|
||||
if uses_usb_otg:
|
||||
self._check_if_can_reset()
|
||||
|
||||
print("Hard resetting via RTS pin...")
|
||||
HardReset(self._port, uses_usb_otg)()
|
||||
|
||||
def change_baud(self, baud):
|
||||
ESPLoader.change_baud(self, baud)
|
||||
|
||||
def check_spi_connection(self, spi_connection):
|
||||
if not set(spi_connection).issubset(set(range(0, 22)) | set(range(26, 47))):
|
||||
raise FatalError("SPI Pin numbers must be in the range 0-21, or 26-46.")
|
||||
if any([v for v in spi_connection if v in [19, 20]]):
|
||||
print(
|
||||
"WARNING: GPIO pins 19 and 20 are used by USB-OTG, "
|
||||
"consider using other pins for SPI flash connection."
|
||||
)
|
||||
|
||||
|
||||
class ESP32S2StubLoader(ESP32S2ROM):
|
||||
"""Access class for ESP32-S2 stub loader, runs on top of ROM.
|
||||
|
||||
(Basically the same as ESP32StubLoader, but different base class.
|
||||
Can possibly be made into a mixin.)
|
||||
"""
|
||||
|
||||
FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c
|
||||
STATUS_BYTES_LENGTH = 2 # same as ESP8266, different to ESP32 ROM
|
||||
IS_STUB = True
|
||||
|
||||
def __init__(self, rom_loader):
|
||||
self.secure_download_mode = rom_loader.secure_download_mode
|
||||
self._port = rom_loader._port
|
||||
self._trace_enabled = rom_loader._trace_enabled
|
||||
self.cache = rom_loader.cache
|
||||
self.flush_input() # resets _slip_reader
|
||||
|
||||
if rom_loader.uses_usb_otg():
|
||||
self.ESP_RAM_BLOCK = self.USB_RAM_BLOCK
|
||||
self.FLASH_WRITE_SIZE = self.USB_RAM_BLOCK
|
||||
|
||||
|
||||
ESP32S2ROM.STUB_CLASS = ESP32S2StubLoader
|
||||
@@ -0,0 +1,387 @@
|
||||
# SPDX-FileCopyrightText: 2014-2023 Fredrik Ahlberg, Angus Gratton,
|
||||
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
import os
|
||||
import struct
|
||||
|
||||
from .esp32 import ESP32ROM
|
||||
from ..loader import ESPLoader
|
||||
from ..reset import HardReset
|
||||
from ..util import FatalError, NotImplementedInROMError
|
||||
|
||||
|
||||
class ESP32S3ROM(ESP32ROM):
|
||||
CHIP_NAME = "ESP32-S3"
|
||||
|
||||
IMAGE_CHIP_ID = 9
|
||||
|
||||
CHIP_DETECT_MAGIC_VALUE = [0x9]
|
||||
|
||||
IROM_MAP_START = 0x42000000
|
||||
IROM_MAP_END = 0x44000000
|
||||
DROM_MAP_START = 0x3C000000
|
||||
DROM_MAP_END = 0x3E000000
|
||||
|
||||
UART_DATE_REG_ADDR = 0x60000080
|
||||
|
||||
SPI_REG_BASE = 0x60002000
|
||||
SPI_USR_OFFS = 0x18
|
||||
SPI_USR1_OFFS = 0x1C
|
||||
SPI_USR2_OFFS = 0x20
|
||||
SPI_MOSI_DLEN_OFFS = 0x24
|
||||
SPI_MISO_DLEN_OFFS = 0x28
|
||||
SPI_W0_OFFS = 0x58
|
||||
|
||||
BOOTLOADER_FLASH_OFFSET = 0x0
|
||||
|
||||
SUPPORTS_ENCRYPTED_FLASH = True
|
||||
|
||||
FLASH_ENCRYPTED_WRITE_ALIGN = 16
|
||||
|
||||
# todo: use espefuse APIs to get this info
|
||||
EFUSE_BASE = 0x60007000 # BLOCK0 read base address
|
||||
EFUSE_BLOCK1_ADDR = EFUSE_BASE + 0x44
|
||||
EFUSE_BLOCK2_ADDR = EFUSE_BASE + 0x5C
|
||||
MAC_EFUSE_REG = EFUSE_BASE + 0x044
|
||||
|
||||
EFUSE_RD_REG_BASE = EFUSE_BASE + 0x030 # BLOCK0 read base address
|
||||
|
||||
EFUSE_PURPOSE_KEY0_REG = EFUSE_BASE + 0x34
|
||||
EFUSE_PURPOSE_KEY0_SHIFT = 24
|
||||
EFUSE_PURPOSE_KEY1_REG = EFUSE_BASE + 0x34
|
||||
EFUSE_PURPOSE_KEY1_SHIFT = 28
|
||||
EFUSE_PURPOSE_KEY2_REG = EFUSE_BASE + 0x38
|
||||
EFUSE_PURPOSE_KEY2_SHIFT = 0
|
||||
EFUSE_PURPOSE_KEY3_REG = EFUSE_BASE + 0x38
|
||||
EFUSE_PURPOSE_KEY3_SHIFT = 4
|
||||
EFUSE_PURPOSE_KEY4_REG = EFUSE_BASE + 0x38
|
||||
EFUSE_PURPOSE_KEY4_SHIFT = 8
|
||||
EFUSE_PURPOSE_KEY5_REG = EFUSE_BASE + 0x38
|
||||
EFUSE_PURPOSE_KEY5_SHIFT = 12
|
||||
|
||||
EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT_REG = EFUSE_RD_REG_BASE
|
||||
EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT = 1 << 20
|
||||
|
||||
EFUSE_SPI_BOOT_CRYPT_CNT_REG = EFUSE_BASE + 0x034
|
||||
EFUSE_SPI_BOOT_CRYPT_CNT_MASK = 0x7 << 18
|
||||
|
||||
EFUSE_SECURE_BOOT_EN_REG = EFUSE_BASE + 0x038
|
||||
EFUSE_SECURE_BOOT_EN_MASK = 1 << 20
|
||||
|
||||
EFUSE_RD_REPEAT_DATA3_REG = EFUSE_BASE + 0x3C
|
||||
EFUSE_RD_REPEAT_DATA3_REG_FLASH_TYPE_MASK = 1 << 9
|
||||
|
||||
PURPOSE_VAL_XTS_AES256_KEY_1 = 2
|
||||
PURPOSE_VAL_XTS_AES256_KEY_2 = 3
|
||||
PURPOSE_VAL_XTS_AES128_KEY = 4
|
||||
|
||||
UARTDEV_BUF_NO = 0x3FCEF14C # Variable in ROM .bss which indicates the port in use
|
||||
UARTDEV_BUF_NO_USB_OTG = 3 # The above var when USB-OTG is used
|
||||
UARTDEV_BUF_NO_USB_JTAG_SERIAL = 4 # The above var when USB-JTAG/Serial is used
|
||||
|
||||
RTCCNTL_BASE_REG = 0x60008000
|
||||
RTC_CNTL_SWD_CONF_REG = RTCCNTL_BASE_REG + 0x00B4
|
||||
RTC_CNTL_SWD_AUTO_FEED_EN = 1 << 31
|
||||
RTC_CNTL_SWD_WPROTECT_REG = RTCCNTL_BASE_REG + 0x00B8
|
||||
RTC_CNTL_SWD_WKEY = 0x8F1D312A
|
||||
|
||||
RTC_CNTL_WDTCONFIG0_REG = RTCCNTL_BASE_REG + 0x0098
|
||||
RTC_CNTL_WDTWPROTECT_REG = RTCCNTL_BASE_REG + 0x00B0
|
||||
RTC_CNTL_WDT_WKEY = 0x50D83AA1
|
||||
|
||||
USB_RAM_BLOCK = 0x800 # Max block size USB-OTG is used
|
||||
|
||||
GPIO_STRAP_REG = 0x60004038
|
||||
GPIO_STRAP_SPI_BOOT_MASK = 0x8 # Not download mode
|
||||
RTC_CNTL_OPTION1_REG = 0x6000812C
|
||||
RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK = 0x1 # Is download mode forced over USB?
|
||||
|
||||
UART_CLKDIV_REG = 0x60000014
|
||||
|
||||
MEMORY_MAP = [
|
||||
[0x00000000, 0x00010000, "PADDING"],
|
||||
[0x3C000000, 0x3D000000, "DROM"],
|
||||
[0x3D000000, 0x3E000000, "EXTRAM_DATA"],
|
||||
[0x600FE000, 0x60100000, "RTC_DRAM"],
|
||||
[0x3FC88000, 0x3FD00000, "BYTE_ACCESSIBLE"],
|
||||
[0x3FC88000, 0x403E2000, "MEM_INTERNAL"],
|
||||
[0x3FC88000, 0x3FD00000, "DRAM"],
|
||||
[0x40000000, 0x4001A100, "IROM_MASK"],
|
||||
[0x40370000, 0x403E0000, "IRAM"],
|
||||
[0x600FE000, 0x60100000, "RTC_IRAM"],
|
||||
[0x42000000, 0x42800000, "IROM"],
|
||||
[0x50000000, 0x50002000, "RTC_DATA"],
|
||||
]
|
||||
|
||||
UF2_FAMILY_ID = 0xC47E5767
|
||||
|
||||
def get_pkg_version(self):
|
||||
num_word = 3
|
||||
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 21) & 0x07
|
||||
|
||||
def is_eco0(self, minor_raw):
|
||||
# Workaround: The major version field was allocated to other purposes
|
||||
# when block version is v1.1.
|
||||
# Luckily only chip v0.0 have this kind of block version and efuse usage.
|
||||
return (
|
||||
(minor_raw & 0x7) == 0
|
||||
and self.get_blk_version_major() == 1
|
||||
and self.get_blk_version_minor() == 1
|
||||
)
|
||||
|
||||
def get_minor_chip_version(self):
|
||||
minor_raw = self.get_raw_minor_chip_version()
|
||||
if self.is_eco0(minor_raw):
|
||||
return 0
|
||||
return minor_raw
|
||||
|
||||
def get_raw_minor_chip_version(self):
|
||||
hi_num_word = 5
|
||||
hi = (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * hi_num_word)) >> 23) & 0x01
|
||||
low_num_word = 3
|
||||
low = (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * low_num_word)) >> 18) & 0x07
|
||||
return (hi << 3) + low
|
||||
|
||||
def get_blk_version_major(self):
|
||||
num_word = 4
|
||||
return (self.read_reg(self.EFUSE_BLOCK2_ADDR + (4 * num_word)) >> 0) & 0x03
|
||||
|
||||
def get_blk_version_minor(self):
|
||||
num_word = 3
|
||||
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 24) & 0x07
|
||||
|
||||
def get_major_chip_version(self):
|
||||
minor_raw = self.get_raw_minor_chip_version()
|
||||
if self.is_eco0(minor_raw):
|
||||
return 0
|
||||
return self.get_raw_major_chip_version()
|
||||
|
||||
def get_raw_major_chip_version(self):
|
||||
num_word = 5
|
||||
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 24) & 0x03
|
||||
|
||||
def get_chip_description(self):
|
||||
major_rev = self.get_major_chip_version()
|
||||
minor_rev = self.get_minor_chip_version()
|
||||
pkg_version = self.get_pkg_version()
|
||||
|
||||
chip_name = {
|
||||
0: "ESP32-S3 (QFN56)",
|
||||
1: "ESP32-S3-PICO-1 (LGA56)",
|
||||
}.get(pkg_version, "unknown ESP32-S3")
|
||||
|
||||
return f"{chip_name} (revision v{major_rev}.{minor_rev})"
|
||||
|
||||
def get_flash_cap(self):
|
||||
num_word = 3
|
||||
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 27) & 0x07
|
||||
|
||||
def get_flash_vendor(self):
|
||||
num_word = 4
|
||||
vendor_id = (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 0) & 0x07
|
||||
return {1: "XMC", 2: "GD", 3: "FM", 4: "TT", 5: "BY"}.get(vendor_id, "")
|
||||
|
||||
def get_psram_cap(self):
|
||||
num_word = 4
|
||||
return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 3) & 0x03
|
||||
|
||||
def get_psram_vendor(self):
|
||||
num_word = 4
|
||||
vendor_id = (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 7) & 0x03
|
||||
return {1: "AP_3v3", 2: "AP_1v8"}.get(vendor_id, "")
|
||||
|
||||
def get_chip_features(self):
|
||||
features = ["WiFi", "BLE"]
|
||||
|
||||
flash = {
|
||||
0: None,
|
||||
1: "Embedded Flash 8MB",
|
||||
2: "Embedded Flash 4MB",
|
||||
}.get(self.get_flash_cap(), "Unknown Embedded Flash")
|
||||
if flash is not None:
|
||||
features += [flash + f" ({self.get_flash_vendor()})"]
|
||||
|
||||
psram = {
|
||||
0: None,
|
||||
1: "Embedded PSRAM 8MB",
|
||||
2: "Embedded PSRAM 2MB",
|
||||
}.get(self.get_psram_cap(), "Unknown Embedded PSRAM")
|
||||
if psram is not None:
|
||||
features += [psram + f" ({self.get_psram_vendor()})"]
|
||||
|
||||
return features
|
||||
|
||||
def get_crystal_freq(self):
|
||||
# ESP32S3 XTAL is fixed to 40MHz
|
||||
return 40
|
||||
|
||||
def get_flash_crypt_config(self):
|
||||
return None # doesn't exist on ESP32-S3
|
||||
|
||||
def get_key_block_purpose(self, key_block):
|
||||
if key_block < 0 or key_block > 5:
|
||||
raise FatalError("Valid key block numbers must be in range 0-5")
|
||||
|
||||
reg, shift = [
|
||||
(self.EFUSE_PURPOSE_KEY0_REG, self.EFUSE_PURPOSE_KEY0_SHIFT),
|
||||
(self.EFUSE_PURPOSE_KEY1_REG, self.EFUSE_PURPOSE_KEY1_SHIFT),
|
||||
(self.EFUSE_PURPOSE_KEY2_REG, self.EFUSE_PURPOSE_KEY2_SHIFT),
|
||||
(self.EFUSE_PURPOSE_KEY3_REG, self.EFUSE_PURPOSE_KEY3_SHIFT),
|
||||
(self.EFUSE_PURPOSE_KEY4_REG, self.EFUSE_PURPOSE_KEY4_SHIFT),
|
||||
(self.EFUSE_PURPOSE_KEY5_REG, self.EFUSE_PURPOSE_KEY5_SHIFT),
|
||||
][key_block]
|
||||
return (self.read_reg(reg) >> shift) & 0xF
|
||||
|
||||
def is_flash_encryption_key_valid(self):
|
||||
# Need to see either an AES-128 key or two AES-256 keys
|
||||
purposes = [self.get_key_block_purpose(b) for b in range(6)]
|
||||
|
||||
if any(p == self.PURPOSE_VAL_XTS_AES128_KEY for p in purposes):
|
||||
return True
|
||||
|
||||
return any(p == self.PURPOSE_VAL_XTS_AES256_KEY_1 for p in purposes) and any(
|
||||
p == self.PURPOSE_VAL_XTS_AES256_KEY_2 for p in purposes
|
||||
)
|
||||
|
||||
def get_secure_boot_enabled(self):
|
||||
return (
|
||||
self.read_reg(self.EFUSE_SECURE_BOOT_EN_REG)
|
||||
& self.EFUSE_SECURE_BOOT_EN_MASK
|
||||
)
|
||||
|
||||
def override_vddsdio(self, new_voltage):
|
||||
raise NotImplementedInROMError(
|
||||
"VDD_SDIO overrides are not supported for ESP32-S3"
|
||||
)
|
||||
|
||||
def read_mac(self, mac_type="BASE_MAC"):
|
||||
"""Read MAC from EFUSE region"""
|
||||
if mac_type != "BASE_MAC":
|
||||
return None
|
||||
mac0 = self.read_reg(self.MAC_EFUSE_REG)
|
||||
mac1 = self.read_reg(self.MAC_EFUSE_REG + 4) # only bottom 16 bits are MAC
|
||||
bitstring = struct.pack(">II", mac1, mac0)[2:]
|
||||
return tuple(bitstring)
|
||||
|
||||
def flash_type(self):
|
||||
return (
|
||||
1
|
||||
if self.read_reg(self.EFUSE_RD_REPEAT_DATA3_REG)
|
||||
& self.EFUSE_RD_REPEAT_DATA3_REG_FLASH_TYPE_MASK
|
||||
else 0
|
||||
)
|
||||
|
||||
def uses_usb_otg(self):
|
||||
"""
|
||||
Check the UARTDEV_BUF_NO register to see if USB-OTG console is being used
|
||||
"""
|
||||
if self.secure_download_mode:
|
||||
return False # can't detect native USB in secure download mode
|
||||
return self.get_uart_no() == self.UARTDEV_BUF_NO_USB_OTG
|
||||
|
||||
def uses_usb_jtag_serial(self):
|
||||
"""
|
||||
Check the UARTDEV_BUF_NO register to see if USB-JTAG/Serial is being used
|
||||
"""
|
||||
if self.secure_download_mode:
|
||||
return False # can't detect USB-JTAG/Serial in secure download mode
|
||||
return self.get_uart_no() == self.UARTDEV_BUF_NO_USB_JTAG_SERIAL
|
||||
|
||||
def disable_watchdogs(self):
|
||||
# When USB-JTAG/Serial is used, the RTC WDT and SWD watchdog are not reset
|
||||
# and can then reset the board during flashing. Disable them.
|
||||
if self.uses_usb_jtag_serial():
|
||||
# Disable RTC WDT
|
||||
self.write_reg(self.RTC_CNTL_WDTWPROTECT_REG, self.RTC_CNTL_WDT_WKEY)
|
||||
self.write_reg(self.RTC_CNTL_WDTCONFIG0_REG, 0)
|
||||
self.write_reg(self.RTC_CNTL_WDTWPROTECT_REG, 0)
|
||||
|
||||
# Automatically feed SWD
|
||||
self.write_reg(self.RTC_CNTL_SWD_WPROTECT_REG, self.RTC_CNTL_SWD_WKEY)
|
||||
self.write_reg(
|
||||
self.RTC_CNTL_SWD_CONF_REG,
|
||||
self.read_reg(self.RTC_CNTL_SWD_CONF_REG)
|
||||
| self.RTC_CNTL_SWD_AUTO_FEED_EN,
|
||||
)
|
||||
self.write_reg(self.RTC_CNTL_SWD_WPROTECT_REG, 0)
|
||||
|
||||
def _post_connect(self):
|
||||
if self.uses_usb_otg():
|
||||
self.ESP_RAM_BLOCK = self.USB_RAM_BLOCK
|
||||
if not self.sync_stub_detected: # Don't run if stub is reused
|
||||
self.disable_watchdogs()
|
||||
|
||||
def _check_if_can_reset(self):
|
||||
"""
|
||||
Check the strapping register to see if we can reset out of download mode.
|
||||
"""
|
||||
if os.getenv("ESPTOOL_TESTING") is not None:
|
||||
print("ESPTOOL_TESTING is set, ignoring strapping mode check")
|
||||
# Esptool tests over USB-OTG run with GPIO0 strapped low,
|
||||
# don't complain in this case.
|
||||
return
|
||||
strap_reg = self.read_reg(self.GPIO_STRAP_REG)
|
||||
force_dl_reg = self.read_reg(self.RTC_CNTL_OPTION1_REG)
|
||||
if (
|
||||
strap_reg & self.GPIO_STRAP_SPI_BOOT_MASK == 0
|
||||
and force_dl_reg & self.RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK == 0
|
||||
):
|
||||
print(
|
||||
"WARNING: {} chip was placed into download mode using GPIO0.\n"
|
||||
"esptool.py can not exit the download mode over USB. "
|
||||
"To run the app, reset the chip manually.\n"
|
||||
"To suppress this note, set --after option to 'no_reset'.".format(
|
||||
self.get_chip_description()
|
||||
)
|
||||
)
|
||||
raise SystemExit(1)
|
||||
|
||||
def hard_reset(self):
|
||||
uses_usb_otg = self.uses_usb_otg()
|
||||
if uses_usb_otg:
|
||||
self._check_if_can_reset()
|
||||
|
||||
print("Hard resetting via RTS pin...")
|
||||
HardReset(self._port, uses_usb_otg)()
|
||||
|
||||
def change_baud(self, baud):
|
||||
ESPLoader.change_baud(self, baud)
|
||||
|
||||
def check_spi_connection(self, spi_connection):
|
||||
if not set(spi_connection).issubset(set(range(0, 22)) | set(range(26, 49))):
|
||||
raise FatalError("SPI Pin numbers must be in the range 0-21, or 26-48.")
|
||||
if spi_connection[3] > 46: # hd_gpio_num must be <= SPI_GPIO_NUM_LIMIT (46)
|
||||
raise FatalError("SPI HD Pin number must be <= 46.")
|
||||
if any([v for v in spi_connection if v in [19, 20]]):
|
||||
print(
|
||||
"WARNING: GPIO pins 19 and 20 are used by USB-Serial/JTAG and USB-OTG, "
|
||||
"consider using other pins for SPI flash connection."
|
||||
)
|
||||
|
||||
|
||||
class ESP32S3StubLoader(ESP32S3ROM):
|
||||
"""Access class for ESP32S3 stub loader, runs on top of ROM.
|
||||
|
||||
(Basically the same as ESP32StubLoader, but different base class.
|
||||
Can possibly be made into a mixin.)
|
||||
"""
|
||||
|
||||
FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c
|
||||
STATUS_BYTES_LENGTH = 2 # same as ESP8266, different to ESP32 ROM
|
||||
IS_STUB = True
|
||||
|
||||
def __init__(self, rom_loader):
|
||||
self.secure_download_mode = rom_loader.secure_download_mode
|
||||
self._port = rom_loader._port
|
||||
self._trace_enabled = rom_loader._trace_enabled
|
||||
self.cache = rom_loader.cache
|
||||
self.flush_input() # resets _slip_reader
|
||||
|
||||
if rom_loader.uses_usb_otg():
|
||||
self.ESP_RAM_BLOCK = self.USB_RAM_BLOCK
|
||||
self.FLASH_WRITE_SIZE = self.USB_RAM_BLOCK
|
||||
|
||||
|
||||
ESP32S3ROM.STUB_CLASS = ESP32S3StubLoader
|
||||
@@ -0,0 +1,37 @@
|
||||
# SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton,
|
||||
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
from .esp32s3 import ESP32S3ROM
|
||||
|
||||
|
||||
class ESP32S3BETA2ROM(ESP32S3ROM):
|
||||
CHIP_NAME = "ESP32-S3(beta2)"
|
||||
IMAGE_CHIP_ID = 4
|
||||
|
||||
CHIP_DETECT_MAGIC_VALUE = [0xEB004136]
|
||||
|
||||
EFUSE_BASE = 0x6001A000 # BLOCK0 read base address
|
||||
|
||||
|
||||
class ESP32S3BETA2StubLoader(ESP32S3BETA2ROM):
|
||||
"""Access class for ESP32S3 stub loader, runs on top of ROM.
|
||||
|
||||
(Basically the same as ESP32StubLoader, but different base class.
|
||||
Can possibly be made into a mixin.)
|
||||
"""
|
||||
|
||||
FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c
|
||||
STATUS_BYTES_LENGTH = 2 # same as ESP8266, different to ESP32 ROM
|
||||
IS_STUB = True
|
||||
|
||||
def __init__(self, rom_loader):
|
||||
self.secure_download_mode = rom_loader.secure_download_mode
|
||||
self._port = rom_loader._port
|
||||
self._trace_enabled = rom_loader._trace_enabled
|
||||
self.cache = rom_loader.cache
|
||||
self.flush_input() # resets _slip_reader
|
||||
|
||||
|
||||
ESP32S3BETA2ROM.STUB_CLASS = ESP32S3BETA2StubLoader
|
||||
@@ -0,0 +1,196 @@
|
||||
# SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton,
|
||||
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
from ..loader import ESPLoader
|
||||
from ..util import FatalError, NotSupportedError
|
||||
|
||||
|
||||
class ESP8266ROM(ESPLoader):
|
||||
"""Access class for ESP8266 ROM bootloader"""
|
||||
|
||||
CHIP_NAME = "ESP8266"
|
||||
IS_STUB = False
|
||||
|
||||
CHIP_DETECT_MAGIC_VALUE = [0xFFF0C101]
|
||||
|
||||
# OTP ROM addresses
|
||||
ESP_OTP_MAC0 = 0x3FF00050
|
||||
ESP_OTP_MAC1 = 0x3FF00054
|
||||
ESP_OTP_MAC3 = 0x3FF0005C
|
||||
|
||||
SPI_REG_BASE = 0x60000200
|
||||
SPI_USR_OFFS = 0x1C
|
||||
SPI_USR1_OFFS = 0x20
|
||||
SPI_USR2_OFFS = 0x24
|
||||
SPI_MOSI_DLEN_OFFS = None
|
||||
SPI_MISO_DLEN_OFFS = None
|
||||
SPI_W0_OFFS = 0x40
|
||||
|
||||
UART_CLKDIV_REG = 0x60000014
|
||||
|
||||
XTAL_CLK_DIVIDER = 2
|
||||
|
||||
FLASH_SIZES = {
|
||||
"512KB": 0x00,
|
||||
"256KB": 0x10,
|
||||
"1MB": 0x20,
|
||||
"2MB": 0x30,
|
||||
"4MB": 0x40,
|
||||
"2MB-c1": 0x50,
|
||||
"4MB-c1": 0x60,
|
||||
"8MB": 0x80,
|
||||
"16MB": 0x90,
|
||||
}
|
||||
|
||||
FLASH_FREQUENCY = {
|
||||
"80m": 0xF,
|
||||
"40m": 0x0,
|
||||
"26m": 0x1,
|
||||
"20m": 0x2,
|
||||
}
|
||||
|
||||
BOOTLOADER_FLASH_OFFSET = 0
|
||||
|
||||
MEMORY_MAP = [
|
||||
[0x3FF00000, 0x3FF00010, "DPORT"],
|
||||
[0x3FFE8000, 0x40000000, "DRAM"],
|
||||
[0x40100000, 0x40108000, "IRAM"],
|
||||
[0x40201010, 0x402E1010, "IROM"],
|
||||
]
|
||||
|
||||
UF2_FAMILY_ID = 0x7EAB61ED
|
||||
|
||||
def get_efuses(self):
|
||||
# Return the 128 bits of ESP8266 efuse as a single Python integer
|
||||
result = self.read_reg(0x3FF0005C) << 96
|
||||
result |= self.read_reg(0x3FF00058) << 64
|
||||
result |= self.read_reg(0x3FF00054) << 32
|
||||
result |= self.read_reg(0x3FF00050)
|
||||
return result
|
||||
|
||||
def _get_flash_size(self, efuses):
|
||||
# rX_Y = EFUSE_DATA_OUTX[Y]
|
||||
r0_4 = (efuses & (1 << 4)) != 0
|
||||
r3_25 = (efuses & (1 << 121)) != 0
|
||||
r3_26 = (efuses & (1 << 122)) != 0
|
||||
r3_27 = (efuses & (1 << 123)) != 0
|
||||
|
||||
if r0_4 and not r3_25:
|
||||
if not r3_27 and not r3_26:
|
||||
return 1
|
||||
elif not r3_27 and r3_26:
|
||||
return 2
|
||||
if not r0_4 and r3_25:
|
||||
if not r3_27 and not r3_26:
|
||||
return 2
|
||||
elif not r3_27 and r3_26:
|
||||
return 4
|
||||
return -1
|
||||
|
||||
def get_chip_description(self):
|
||||
efuses = self.get_efuses()
|
||||
is_8285 = (
|
||||
efuses & ((1 << 4) | 1 << 80)
|
||||
) != 0 # One or the other efuse bit is set for ESP8285
|
||||
if is_8285:
|
||||
flash_size = self._get_flash_size(efuses)
|
||||
max_temp = (
|
||||
efuses & (1 << 5)
|
||||
) != 0 # This efuse bit identifies the max flash temperature
|
||||
chip_name = {
|
||||
1: "ESP8285H08" if max_temp else "ESP8285N08",
|
||||
2: "ESP8285H16" if max_temp else "ESP8285N16",
|
||||
}.get(flash_size, "ESP8285")
|
||||
return chip_name
|
||||
return "ESP8266EX"
|
||||
|
||||
def get_chip_features(self):
|
||||
features = ["WiFi"]
|
||||
if "ESP8285" in self.get_chip_description():
|
||||
features += ["Embedded Flash"]
|
||||
return features
|
||||
|
||||
def flash_spi_attach(self, hspi_arg):
|
||||
if self.IS_STUB:
|
||||
super(ESP8266ROM, self).flash_spi_attach(hspi_arg)
|
||||
else:
|
||||
# ESP8266 ROM has no flash_spi_attach command in serial protocol,
|
||||
# but flash_begin will do it
|
||||
self.flash_begin(0, 0)
|
||||
|
||||
def flash_set_parameters(self, size):
|
||||
# not implemented in ROM, but OK to silently skip for ROM
|
||||
if self.IS_STUB:
|
||||
super(ESP8266ROM, self).flash_set_parameters(size)
|
||||
|
||||
def chip_id(self):
|
||||
"""
|
||||
Read Chip ID from efuse - the equivalent of the SDK system_get_chip_id() func
|
||||
"""
|
||||
id0 = self.read_reg(self.ESP_OTP_MAC0)
|
||||
id1 = self.read_reg(self.ESP_OTP_MAC1)
|
||||
return (id0 >> 24) | ((id1 & 0xFFFFFF) << 8)
|
||||
|
||||
def read_mac(self, mac_type="BASE_MAC"):
|
||||
"""Read MAC from OTP ROM"""
|
||||
if mac_type != "BASE_MAC":
|
||||
return None
|
||||
mac0 = self.read_reg(self.ESP_OTP_MAC0)
|
||||
mac1 = self.read_reg(self.ESP_OTP_MAC1)
|
||||
mac3 = self.read_reg(self.ESP_OTP_MAC3)
|
||||
if mac3 != 0:
|
||||
oui = ((mac3 >> 16) & 0xFF, (mac3 >> 8) & 0xFF, mac3 & 0xFF)
|
||||
elif ((mac1 >> 16) & 0xFF) == 0:
|
||||
oui = (0x18, 0xFE, 0x34)
|
||||
elif ((mac1 >> 16) & 0xFF) == 1:
|
||||
oui = (0xAC, 0xD0, 0x74)
|
||||
else:
|
||||
raise FatalError("Unknown OUI")
|
||||
return oui + ((mac1 >> 8) & 0xFF, mac1 & 0xFF, (mac0 >> 24) & 0xFF)
|
||||
|
||||
def get_erase_size(self, offset, size):
|
||||
"""Calculate an erase size given a specific size in bytes.
|
||||
|
||||
Provides a workaround for the bootloader erase bug."""
|
||||
|
||||
sectors_per_block = 16
|
||||
sector_size = self.FLASH_SECTOR_SIZE
|
||||
num_sectors = (size + sector_size - 1) // sector_size
|
||||
start_sector = offset // sector_size
|
||||
|
||||
head_sectors = sectors_per_block - (start_sector % sectors_per_block)
|
||||
if num_sectors < head_sectors:
|
||||
head_sectors = num_sectors
|
||||
|
||||
if num_sectors < 2 * head_sectors:
|
||||
return (num_sectors + 1) // 2 * sector_size
|
||||
else:
|
||||
return (num_sectors - head_sectors) * sector_size
|
||||
|
||||
def override_vddsdio(self, new_voltage):
|
||||
raise NotSupportedError(self, "Overriding VDDSDIO")
|
||||
|
||||
def check_spi_connection(self, spi_connection):
|
||||
raise NotSupportedError(self, "Setting --spi-connection")
|
||||
|
||||
|
||||
class ESP8266StubLoader(ESP8266ROM):
|
||||
"""Access class for ESP8266 stub loader, runs on top of ROM."""
|
||||
|
||||
FLASH_WRITE_SIZE = 0x4000 # matches MAX_WRITE_BLOCK in stub_loader.c
|
||||
IS_STUB = True
|
||||
|
||||
def __init__(self, rom_loader):
|
||||
self.secure_download_mode = rom_loader.secure_download_mode
|
||||
self._port = rom_loader._port
|
||||
self._trace_enabled = rom_loader._trace_enabled
|
||||
self.cache = rom_loader.cache
|
||||
self.flush_input() # resets _slip_reader
|
||||
|
||||
def get_erase_size(self, offset, size):
|
||||
return size # stub doesn't have same size bug as ROM loader
|
||||
|
||||
|
||||
ESP8266ROM.STUB_CLASS = ESP8266StubLoader
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"entry": 1074521580,
|
||||
"text": "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",
|
||||
"text_start": 1074520064,
|
||||
"data": "DMD8P+znC0B/6AtAZ+0LQAbpC0Cf6AtABukLQGXpC0CC6gtA9OoLQJ3qC0CV5wtAGuoLQHTqC0CI6QtAGOsLQLDpC0AY6wtAbegLQMroC0AG6QtAZekLQIXoC0DI6wtAKe0LQLjmC0BL7QtAuOYLQLjmC0C45gtAuOYLQLjmC0C45gtAuOYLQLjmC0Bv6wtAuOYLQEnsC0Ap7QtA",
|
||||
"data_start": 1073605544,
|
||||
"bss_start": 1073528832
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"entry": 1077413304,
|
||||
"text": "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",
|
||||
"text_start": 1077411840,
|
||||
"data": "DEDKP+AIOEAsCThAhAk4QFIKOEC+CjhAbAo4QKgHOEAOCjhATgo4QJgJOEBYBzhAzAk4QFgHOEC6CDhA/gg4QCwJOECECThAzAg4QBIIOEBCCDhAyAg4QBYNOEAsCThA1gs4QMoMOECkBjhA9Aw4QKQGOECkBjhApAY4QKQGOECkBjhApAY4QKQGOECkBjhAcgs4QKQGOEDyCzhAygw4QA==",
|
||||
"data_start": 1070295976,
|
||||
"bss_start": 1070219264
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"entry": 1077413318,
|
||||
"text": "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",
|
||||
"text_start": 1077411840,
|
||||
"data": "DEDIP/gIOEBECThAnAk4QGoKOEDWCjhAhAo4QMAHOEAmCjhAZgo4QLAJOEBwBzhA5Ak4QHAHOEDSCDhAFgk4QEQJOECcCThA5Ag4QCoIOEBaCDhA4Ag4QC4NOEBECThA7gs4QOIMOEC8BjhADA04QLwGOEC8BjhAvAY4QLwGOEC8BjhAvAY4QLwGOEC8BjhAigs4QLwGOEAKDDhA4gw4QA==",
|
||||
"data_start": 1070164904,
|
||||
"bss_start": 1070088192
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"entry": 1077413318,
|
||||
"text": "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",
|
||||
"text_start": 1077411840,
|
||||
"data": "DEDIP/gIOEBECThAnAk4QGoKOEDWCjhAhAo4QMAHOEAmCjhAZgo4QLAJOEBwBzhA5Ak4QHAHOEDSCDhAFgk4QEQJOECcCThA5Ag4QCoIOEBaCDhA4Ag4QC4NOEBECThA7gs4QOIMOEC8BjhADA04QLwGOEC8BjhAvAY4QLwGOEC8BjhAvAY4QLwGOEC8BjhAigs4QLwGOEAKDDhA4gw4QA==",
|
||||
"data_start": 1070164904,
|
||||
"bss_start": 1070088192
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"entry": 1077413318,
|
||||
"text": "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",
|
||||
"text_start": 1077411840,
|
||||
"data": "DEDIP/gIOEBECThAnAk4QGoKOEDWCjhAhAo4QMAHOEAmCjhAZgo4QLAJOEBwBzhA5Ak4QHAHOEDSCDhAFgk4QEQJOECcCThA5Ag4QCoIOEBaCDhA4Ag4QC4NOEBECThA7gs4QOIMOEC8BjhADA04QLwGOEC8BjhAvAY4QLwGOEC8BjhAvAY4QLwGOEC8BjhAigs4QLwGOEAKDDhA4gw4QA==",
|
||||
"data_start": 1070164904,
|
||||
"bss_start": 1070088192
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"entry": 1341195718,
|
||||
"text": "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",
|
||||
"text_start": 1341194240,
|
||||
"data": "DAD1T+4I8U86CfFPkgnxT2gK8U/UCvFPggrxT7YH8U8kCvFPZArxT6YJ8U9mB/FP2gnxT2YH8U/ICPFPDAnxTzoJ8U+SCfFP2gjxTyAI8U9QCPFP1gjxTywN8U86CfFP7AvxT+AM8U+yBvFPCg3xT7IG8U+yBvFPsgbxT7IG8U+yBvFPsgbxT7IG8U+yBvFPiAvxT7IG8U8IDPFP4AzxTw==",
|
||||
"data_start": 1341533096,
|
||||
"bss_start": 1341456384
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"entry": 1077380596,
|
||||
"text": "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",
|
||||
"text_start": 1077379072,
|
||||
"data": "DADKPxeIN0CriDdAw403QDeJN0DLiDdAN4k3QJaJN0C2ijdAKIs3QNGKN0ChhzdASIo3QKiKN0C5iTdATIs3QOGJN0BMizdAmYg3QPiIN0A3iTdAlok3QLGIN0DjhzdABIw3QIWNN0DAhjdAp403QMCGN0DAhjdAwIY3QMCGN0DAhjdAwIY3QMCGN0DAhjdAqYs3QMCGN0CZjDdAhY03QA==",
|
||||
"data_start": 1070279592,
|
||||
"bss_start": 1070202880
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,96 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
# Code was originally licensed under Apache 2.0 before the release of ESP-IDF v5.2
|
||||
|
||||
import hashlib
|
||||
import os
|
||||
import struct
|
||||
from typing import List
|
||||
|
||||
from esptool.util import div_roundup
|
||||
|
||||
|
||||
class UF2Writer(object):
|
||||
# The UF2 format is described here: https://github.com/microsoft/uf2
|
||||
UF2_BLOCK_SIZE = 512
|
||||
# max value of CHUNK_SIZE reduced by optional parts. Currently, MD5_PART only.
|
||||
UF2_DATA_SIZE = 476
|
||||
UF2_MD5_PART_SIZE = 24
|
||||
UF2_FIRST_MAGIC = 0x0A324655
|
||||
UF2_SECOND_MAGIC = 0x9E5D5157
|
||||
UF2_FINAL_MAGIC = 0x0AB16F30
|
||||
UF2_FLAG_FAMILYID_PRESENT = 0x00002000
|
||||
UF2_FLAG_MD5_PRESENT = 0x00004000
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
chip_id: int,
|
||||
output_file: os.PathLike,
|
||||
chunk_size: int,
|
||||
md5_enabled: bool = True,
|
||||
) -> None:
|
||||
if not md5_enabled:
|
||||
self.UF2_MD5_PART_SIZE = 0
|
||||
self.UF2_FLAG_MD5_PRESENT = 0x00000000
|
||||
self.md5_enabled = md5_enabled
|
||||
self.chip_id = chip_id
|
||||
self.CHUNK_SIZE = (
|
||||
self.UF2_DATA_SIZE - self.UF2_MD5_PART_SIZE
|
||||
if chunk_size is None
|
||||
else chunk_size
|
||||
)
|
||||
self.f = open(output_file, "wb")
|
||||
|
||||
def __enter__(self) -> "UF2Writer":
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type: str, exc_val: int, exc_tb: List) -> None:
|
||||
if self.f:
|
||||
self.f.close()
|
||||
|
||||
@staticmethod
|
||||
def _to_uint32(num: int) -> bytes:
|
||||
return struct.pack("<I", num)
|
||||
|
||||
def _write_block(
|
||||
self, addr: int, chunk: bytes, len_chunk: int, block_no: int, blocks: int
|
||||
) -> None:
|
||||
assert len_chunk > 0
|
||||
assert len_chunk <= self.CHUNK_SIZE
|
||||
assert block_no < blocks
|
||||
block = struct.pack(
|
||||
"<IIIIIIII",
|
||||
self.UF2_FIRST_MAGIC,
|
||||
self.UF2_SECOND_MAGIC,
|
||||
self.UF2_FLAG_FAMILYID_PRESENT | self.UF2_FLAG_MD5_PRESENT,
|
||||
addr,
|
||||
len_chunk,
|
||||
block_no,
|
||||
blocks,
|
||||
self.chip_id,
|
||||
)
|
||||
block += chunk
|
||||
|
||||
if self.md5_enabled:
|
||||
md5_part = struct.pack("<II", addr, len_chunk)
|
||||
md5_part += hashlib.md5(chunk).digest()
|
||||
assert len(md5_part) == self.UF2_MD5_PART_SIZE
|
||||
|
||||
block += md5_part
|
||||
block += b"\x00" * (self.UF2_DATA_SIZE - self.UF2_MD5_PART_SIZE - len_chunk)
|
||||
block += self._to_uint32(self.UF2_FINAL_MAGIC)
|
||||
assert len(block) == self.UF2_BLOCK_SIZE
|
||||
self.f.write(block)
|
||||
|
||||
def add_file(self, addr: int, image: bytes) -> None:
|
||||
blocks = div_roundup(len(image), self.CHUNK_SIZE)
|
||||
chunks = [
|
||||
image[i : i + self.CHUNK_SIZE]
|
||||
for i in range(0, len(image), self.CHUNK_SIZE)
|
||||
]
|
||||
for i, chunk in enumerate(chunks):
|
||||
len_chunk = len(chunk)
|
||||
self._write_block(addr, chunk, len_chunk, i, blocks)
|
||||
addr += len_chunk
|
||||
186
code/.venv/lib/python3.12/site-packages/esptool/util.py
Normal file
186
code/.venv/lib/python3.12/site-packages/esptool/util.py
Normal file
@@ -0,0 +1,186 @@
|
||||
# SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton,
|
||||
# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
import os
|
||||
import re
|
||||
import struct
|
||||
import sys
|
||||
|
||||
|
||||
def byte(bitstr, index):
|
||||
return bitstr[index]
|
||||
|
||||
|
||||
def mask_to_shift(mask):
|
||||
"""Return the index of the least significant bit in the mask"""
|
||||
shift = 0
|
||||
while mask & 0x1 == 0:
|
||||
shift += 1
|
||||
mask >>= 1
|
||||
return shift
|
||||
|
||||
|
||||
def div_roundup(a, b):
|
||||
"""Return a/b rounded up to nearest integer,
|
||||
equivalent result to int(math.ceil(float(int(a)) / float(int(b))), only
|
||||
without possible floating point accuracy errors.
|
||||
"""
|
||||
return (int(a) + int(b) - 1) // int(b)
|
||||
|
||||
|
||||
def flash_size_bytes(size):
|
||||
"""Given a flash size of the type passed in args.flash_size
|
||||
(ie 512KB or 1MB) then return the size in bytes.
|
||||
"""
|
||||
if size is None:
|
||||
return None
|
||||
if "MB" in size:
|
||||
return int(size[: size.index("MB")]) * 1024 * 1024
|
||||
elif "KB" in size:
|
||||
return int(size[: size.index("KB")]) * 1024
|
||||
else:
|
||||
raise FatalError("Unknown size %s" % size)
|
||||
|
||||
|
||||
def hexify(s, uppercase=True):
|
||||
format_str = "%02X" if uppercase else "%02x"
|
||||
return "".join(format_str % c for c in s)
|
||||
|
||||
|
||||
def pad_to(data, alignment, pad_character=b"\xFF"):
|
||||
"""Pad to the next alignment boundary"""
|
||||
pad_mod = len(data) % alignment
|
||||
if pad_mod != 0:
|
||||
data += pad_character * (alignment - pad_mod)
|
||||
return data
|
||||
|
||||
|
||||
def print_overwrite(message, last_line=False):
|
||||
"""Print a message, overwriting the currently printed line.
|
||||
|
||||
If last_line is False, don't append a newline at the end
|
||||
(expecting another subsequent call will overwrite this one.)
|
||||
|
||||
After a sequence of calls with last_line=False, call once with last_line=True.
|
||||
|
||||
If output is not a TTY (for example redirected a pipe),
|
||||
no overwriting happens and this function is the same as print().
|
||||
"""
|
||||
if hasattr(sys.stdout, "isatty") and sys.stdout.isatty():
|
||||
print("\r%s" % message, end="\n" if last_line else "")
|
||||
else:
|
||||
print(message)
|
||||
|
||||
|
||||
def expand_chip_name(chip_name):
|
||||
"""Change chip name to official form, e.g. `esp32s3beta2` -> `ESP32-S3(beta2)`"""
|
||||
# Put "-" after "esp32"
|
||||
chip_name = re.sub(r"(esp32)(?!$)", r"\1-", chip_name)
|
||||
# Put "()" around "betaN"
|
||||
chip_name = re.sub(r"(beta\d*)", r"(\1)", chip_name)
|
||||
# Uppercase everything before "(betaN)"
|
||||
chip_name = re.sub(r"^[^\(]+", lambda x: x.group(0).upper(), chip_name)
|
||||
return chip_name
|
||||
|
||||
|
||||
def strip_chip_name(chip_name):
|
||||
"""Strip chip name to normalized form, e.g. `ESP32-S3(beta2)` -> `esp32s3beta2`"""
|
||||
return re.sub(r"[-()]", "", chip_name.lower())
|
||||
|
||||
|
||||
def get_file_size(path_to_file):
|
||||
"""Returns the file size in bytes"""
|
||||
file_size = 0
|
||||
with open(path_to_file, "rb") as f:
|
||||
f.seek(0, os.SEEK_END)
|
||||
file_size = f.tell()
|
||||
return file_size
|
||||
|
||||
|
||||
class FatalError(RuntimeError):
|
||||
"""
|
||||
Wrapper class for runtime errors that aren't caused by internal bugs, but by
|
||||
ESP ROM responses or input content.
|
||||
"""
|
||||
|
||||
def __init__(self, message):
|
||||
RuntimeError.__init__(self, message)
|
||||
|
||||
@staticmethod
|
||||
def WithResult(message, result):
|
||||
"""
|
||||
Return a fatal error object that appends the hex values of
|
||||
'result' and its meaning as a string formatted argument.
|
||||
"""
|
||||
|
||||
err_defs = {
|
||||
# ROM error codes
|
||||
0x101: "Out of memory",
|
||||
0x102: "Invalid argument",
|
||||
0x103: "Invalid state",
|
||||
0x104: "Invalid size",
|
||||
0x105: "Requested resource not found",
|
||||
0x106: "Operation or feature not supported",
|
||||
0x107: "Operation timed out",
|
||||
0x108: "Received response was invalid",
|
||||
0x109: "CRC or checksum was invalid",
|
||||
0x10A: "Version was invalid",
|
||||
0x10B: "MAC address was invalid",
|
||||
# Flasher stub error codes
|
||||
0xC000: "Bad data length",
|
||||
0xC100: "Bad data checksum",
|
||||
0xC200: "Bad blocksize",
|
||||
0xC300: "Invalid command",
|
||||
0xC400: "Failed SPI operation",
|
||||
0xC500: "Failed SPI unlock",
|
||||
0xC600: "Not in flash mode",
|
||||
0xC700: "Inflate error",
|
||||
0xC800: "Not enough data",
|
||||
0xC900: "Too much data",
|
||||
0xFF00: "Command not implemented",
|
||||
}
|
||||
|
||||
err_code = struct.unpack(">H", result[:2])
|
||||
message += " (result was {}: {})".format(
|
||||
hexify(result), err_defs.get(err_code[0], "Unknown result")
|
||||
)
|
||||
return FatalError(message)
|
||||
|
||||
|
||||
class NotImplementedInROMError(FatalError):
|
||||
"""
|
||||
Wrapper class for the error thrown when a particular ESP bootloader function
|
||||
is not implemented in the ROM bootloader.
|
||||
"""
|
||||
|
||||
def __init__(self, bootloader, func):
|
||||
FatalError.__init__(
|
||||
self,
|
||||
"%s ROM does not support function %s."
|
||||
% (bootloader.CHIP_NAME, func.__name__),
|
||||
)
|
||||
|
||||
|
||||
class NotSupportedError(FatalError):
|
||||
def __init__(self, esp, function_name):
|
||||
FatalError.__init__(
|
||||
self,
|
||||
f"{function_name} is not supported by {esp.CHIP_NAME}.",
|
||||
)
|
||||
|
||||
|
||||
class UnsupportedCommandError(RuntimeError):
|
||||
"""
|
||||
Wrapper class for when ROM loader returns an invalid command response.
|
||||
|
||||
Usually this indicates the loader is running in Secure Download Mode.
|
||||
"""
|
||||
|
||||
def __init__(self, esp, op):
|
||||
if esp.secure_download_mode:
|
||||
msg = "This command (0x%x) is not supported in Secure Download Mode" % op
|
||||
else:
|
||||
msg = "Invalid (unsupported) command 0x%x" % op
|
||||
RuntimeError.__init__(self, msg)
|
||||
Reference in New Issue
Block a user