1# SPDX-FileCopyrightText: 2014-2022 Fredrik Ahlberg, Angus Gratton,
2# Espressif Systems (Shanghai) CO LTD, other contributors as noted.
3#
4# SPDX-License-Identifier: GPL-2.0-or-later
5
6import struct
7from typing import Dict
8
9from .esp32 import ESP32ROM
10from ..loader import ESPLoader
11from ..util import FatalError, NotImplementedInROMError
12
13
14class ESP32C3ROM(ESP32ROM):
15    CHIP_NAME = "ESP32-C3"
16    IMAGE_CHIP_ID = 5
17
18    IROM_MAP_START = 0x42000000
19    IROM_MAP_END = 0x42800000
20    DROM_MAP_START = 0x3C000000
21    DROM_MAP_END = 0x3C800000
22
23    SPI_REG_BASE = 0x60002000
24    SPI_USR_OFFS = 0x18
25    SPI_USR1_OFFS = 0x1C
26    SPI_USR2_OFFS = 0x20
27    SPI_MOSI_DLEN_OFFS = 0x24
28    SPI_MISO_DLEN_OFFS = 0x28
29    SPI_W0_OFFS = 0x58
30
31    SPI_ADDR_REG_MSB = False
32
33    BOOTLOADER_FLASH_OFFSET = 0x0
34
35    # Magic values for ESP32-C3 eco 1+2, eco 3, eco 6, and eco 7 respectively
36    CHIP_DETECT_MAGIC_VALUE = [0x6921506F, 0x1B31506F, 0x4881606F, 0x4361606F]
37
38    UART_DATE_REG_ADDR = 0x60000000 + 0x7C
39
40    UART_CLKDIV_REG = 0x60000014
41
42    EFUSE_BASE = 0x60008800
43    EFUSE_BLOCK1_ADDR = EFUSE_BASE + 0x044
44    MAC_EFUSE_REG = EFUSE_BASE + 0x044
45
46    EFUSE_RD_REG_BASE = EFUSE_BASE + 0x030  # BLOCK0 read base address
47
48    EFUSE_PURPOSE_KEY0_REG = EFUSE_BASE + 0x34
49    EFUSE_PURPOSE_KEY0_SHIFT = 24
50    EFUSE_PURPOSE_KEY1_REG = EFUSE_BASE + 0x34
51    EFUSE_PURPOSE_KEY1_SHIFT = 28
52    EFUSE_PURPOSE_KEY2_REG = EFUSE_BASE + 0x38
53    EFUSE_PURPOSE_KEY2_SHIFT = 0
54    EFUSE_PURPOSE_KEY3_REG = EFUSE_BASE + 0x38
55    EFUSE_PURPOSE_KEY3_SHIFT = 4
56    EFUSE_PURPOSE_KEY4_REG = EFUSE_BASE + 0x38
57    EFUSE_PURPOSE_KEY4_SHIFT = 8
58    EFUSE_PURPOSE_KEY5_REG = EFUSE_BASE + 0x38
59    EFUSE_PURPOSE_KEY5_SHIFT = 12
60
61    EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT_REG = EFUSE_RD_REG_BASE
62    EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT = 1 << 20
63
64    EFUSE_SPI_BOOT_CRYPT_CNT_REG = EFUSE_BASE + 0x034
65    EFUSE_SPI_BOOT_CRYPT_CNT_MASK = 0x7 << 18
66
67    EFUSE_SECURE_BOOT_EN_REG = EFUSE_BASE + 0x038
68    EFUSE_SECURE_BOOT_EN_MASK = 1 << 20
69
70    PURPOSE_VAL_XTS_AES128_KEY = 4
71
72    SUPPORTS_ENCRYPTED_FLASH = True
73
74    FLASH_ENCRYPTED_WRITE_ALIGN = 16
75
76    UARTDEV_BUF_NO = 0x3FCDF07C  # Variable in ROM .bss which indicates the port in use
77    UARTDEV_BUF_NO_USB_JTAG_SERIAL = 3  # The above var when USB-JTAG/Serial is used
78
79    RTCCNTL_BASE_REG = 0x60008000
80    RTC_CNTL_SWD_CONF_REG = RTCCNTL_BASE_REG + 0x00AC
81    RTC_CNTL_SWD_AUTO_FEED_EN = 1 << 31
82    RTC_CNTL_SWD_WPROTECT_REG = RTCCNTL_BASE_REG + 0x00B0
83    RTC_CNTL_SWD_WKEY = 0x8F1D312A
84
85    RTC_CNTL_WDTCONFIG0_REG = RTCCNTL_BASE_REG + 0x0090
86    RTC_CNTL_WDTWPROTECT_REG = RTCCNTL_BASE_REG + 0x00A8
87    RTC_CNTL_WDT_WKEY = 0x50D83AA1
88
89    MEMORY_MAP = [
90        [0x00000000, 0x00010000, "PADDING"],
91        [0x3C000000, 0x3C800000, "DROM"],
92        [0x3FC80000, 0x3FCE0000, "DRAM"],
93        [0x3FC88000, 0x3FD00000, "BYTE_ACCESSIBLE"],
94        [0x3FF00000, 0x3FF20000, "DROM_MASK"],
95        [0x40000000, 0x40060000, "IROM_MASK"],
96        [0x42000000, 0x42800000, "IROM"],
97        [0x4037C000, 0x403E0000, "IRAM"],
98        [0x50000000, 0x50002000, "RTC_IRAM"],
99        [0x50000000, 0x50002000, "RTC_DRAM"],
100        [0x600FE000, 0x60100000, "MEM_INTERNAL2"],
101    ]
102
103    UF2_FAMILY_ID = 0xD42BA06C
104
105    EFUSE_MAX_KEY = 5
106    KEY_PURPOSES: Dict[int, str] = {
107        0: "USER/EMPTY",
108        1: "RESERVED",
109        4: "XTS_AES_128_KEY",
110        5: "HMAC_DOWN_ALL",
111        6: "HMAC_DOWN_JTAG",
112        7: "HMAC_DOWN_DIGITAL_SIGNATURE",
113        8: "HMAC_UP",
114        9: "SECURE_BOOT_DIGEST0",
115        10: "SECURE_BOOT_DIGEST1",
116        11: "SECURE_BOOT_DIGEST2",
117    }
118
119    def get_pkg_version(self):
120        num_word = 3
121        return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 21) & 0x07
122
123    def get_minor_chip_version(self):
124        hi_num_word = 5
125        hi = (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * hi_num_word)) >> 23) & 0x01
126        low_num_word = 3
127        low = (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * low_num_word)) >> 18) & 0x07
128        return (hi << 3) + low
129
130    def get_major_chip_version(self):
131        num_word = 5
132        return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 24) & 0x03
133
134    def get_flash_cap(self):
135        num_word = 3
136        return (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 27) & 0x07
137
138    def get_flash_vendor(self):
139        num_word = 4
140        vendor_id = (self.read_reg(self.EFUSE_BLOCK1_ADDR + (4 * num_word)) >> 0) & 0x07
141        return {1: "XMC", 2: "GD", 3: "FM", 4: "TT", 5: "ZBIT"}.get(vendor_id, "")
142
143    def get_chip_description(self):
144        chip_name = {
145            0: "ESP32-C3 (QFN32)",
146            1: "ESP8685 (QFN28)",
147            2: "ESP32-C3 AZ (QFN32)",
148            3: "ESP8686 (QFN24)",
149        }.get(self.get_pkg_version(), "unknown ESP32-C3")
150        major_rev = self.get_major_chip_version()
151        minor_rev = self.get_minor_chip_version()
152        return f"{chip_name} (revision v{major_rev}.{minor_rev})"
153
154    def get_chip_features(self):
155        features = ["WiFi", "BLE"]
156
157        flash = {
158            0: None,
159            1: "Embedded Flash 4MB",
160            2: "Embedded Flash 2MB",
161            3: "Embedded Flash 1MB",
162            4: "Embedded Flash 8MB",
163        }.get(self.get_flash_cap(), "Unknown Embedded Flash")
164        if flash is not None:
165            features += [flash + f" ({self.get_flash_vendor()})"]
166        return features
167
168    def get_crystal_freq(self):
169        # ESP32C3 XTAL is fixed to 40MHz
170        return 40
171
172    def get_flash_voltage(self):
173        pass  # not supported on ESP32-C3
174
175    def override_vddsdio(self, new_voltage):
176        raise NotImplementedInROMError(
177            "VDD_SDIO overrides are not supported for ESP32-C3"
178        )
179
180    def read_mac(self, mac_type="BASE_MAC"):
181        """Read MAC from EFUSE region"""
182        if mac_type != "BASE_MAC":
183            return None
184        mac0 = self.read_reg(self.MAC_EFUSE_REG)
185        mac1 = self.read_reg(self.MAC_EFUSE_REG + 4)  # only bottom 16 bits are MAC
186        bitstring = struct.pack(">II", mac1, mac0)[2:]
187        return tuple(bitstring)
188
189    def get_flash_crypt_config(self):
190        return None  # doesn't exist on ESP32-C3
191
192    def get_secure_boot_enabled(self):
193        return (
194            self.read_reg(self.EFUSE_SECURE_BOOT_EN_REG)
195            & self.EFUSE_SECURE_BOOT_EN_MASK
196        )
197
198    def get_key_block_purpose(self, key_block):
199        if key_block < 0 or key_block > self.EFUSE_MAX_KEY:
200            raise FatalError(
201                f"Valid key block numbers must be in range 0-{self.EFUSE_MAX_KEY}"
202            )
203
204        reg, shift = [
205            (self.EFUSE_PURPOSE_KEY0_REG, self.EFUSE_PURPOSE_KEY0_SHIFT),
206            (self.EFUSE_PURPOSE_KEY1_REG, self.EFUSE_PURPOSE_KEY1_SHIFT),
207            (self.EFUSE_PURPOSE_KEY2_REG, self.EFUSE_PURPOSE_KEY2_SHIFT),
208            (self.EFUSE_PURPOSE_KEY3_REG, self.EFUSE_PURPOSE_KEY3_SHIFT),
209            (self.EFUSE_PURPOSE_KEY4_REG, self.EFUSE_PURPOSE_KEY4_SHIFT),
210            (self.EFUSE_PURPOSE_KEY5_REG, self.EFUSE_PURPOSE_KEY5_SHIFT),
211        ][key_block]
212        return (self.read_reg(reg) >> shift) & 0xF
213
214    def is_flash_encryption_key_valid(self):
215        # Need to see an AES-128 key
216        purposes = [
217            self.get_key_block_purpose(b) for b in range(self.EFUSE_MAX_KEY + 1)
218        ]
219
220        return any(p == self.PURPOSE_VAL_XTS_AES128_KEY for p in purposes)
221
222    def change_baud(self, baud):
223        ESPLoader.change_baud(self, baud)
224
225    def uses_usb_jtag_serial(self):
226        """
227        Check the UARTDEV_BUF_NO register to see if USB-JTAG/Serial is being used
228        """
229        if self.secure_download_mode:
230            return False  # Can't detect USB-JTAG/Serial in secure download mode
231        return self.get_uart_no() == self.UARTDEV_BUF_NO_USB_JTAG_SERIAL
232
233    def disable_watchdogs(self):
234        # When USB-JTAG/Serial is used, the RTC WDT and SWD watchdog are not reset
235        # and can then reset the board during flashing. Disable or autofeed them.
236        if self.uses_usb_jtag_serial():
237            # Disable RTC WDT
238            self.write_reg(self.RTC_CNTL_WDTWPROTECT_REG, self.RTC_CNTL_WDT_WKEY)
239            self.write_reg(self.RTC_CNTL_WDTCONFIG0_REG, 0)
240            self.write_reg(self.RTC_CNTL_WDTWPROTECT_REG, 0)
241
242            # Automatically feed SWD
243            self.write_reg(self.RTC_CNTL_SWD_WPROTECT_REG, self.RTC_CNTL_SWD_WKEY)
244            self.write_reg(
245                self.RTC_CNTL_SWD_CONF_REG,
246                self.read_reg(self.RTC_CNTL_SWD_CONF_REG)
247                | self.RTC_CNTL_SWD_AUTO_FEED_EN,
248            )
249            self.write_reg(self.RTC_CNTL_SWD_WPROTECT_REG, 0)
250
251    def _post_connect(self):
252        if not self.sync_stub_detected:  # Don't run if stub is reused
253            self.disable_watchdogs()
254
255    def check_spi_connection(self, spi_connection):
256        if not set(spi_connection).issubset(set(range(0, 22))):
257            raise FatalError("SPI Pin numbers must be in the range 0-21.")
258        if any([v for v in spi_connection if v in [18, 19]]):
259            print(
260                "WARNING: GPIO pins 18 and 19 are used by USB-Serial/JTAG, "
261                "consider using other pins for SPI flash connection."
262            )
263
264
265class ESP32C3StubLoader(ESP32C3ROM):
266    """Access class for ESP32C3 stub loader, runs on top of ROM.
267
268    (Basically the same as ESP32StubLoader, but different base class.
269    Can possibly be made into a mixin.)
270    """
271
272    FLASH_WRITE_SIZE = 0x4000  # matches MAX_WRITE_BLOCK in stub_loader.c
273    STATUS_BYTES_LENGTH = 2  # same as ESP8266, different to ESP32 ROM
274    IS_STUB = True
275
276    def __init__(self, rom_loader):
277        self.secure_download_mode = rom_loader.secure_download_mode
278        self._port = rom_loader._port
279        self._trace_enabled = rom_loader._trace_enabled
280        self.cache = rom_loader.cache
281        self.flush_input()  # resets _slip_reader
282
283
284ESP32C3ROM.STUB_CLASS = ESP32C3StubLoader
285