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
7import time
8from typing import Dict, Optional
9
10from ..loader import ESPLoader
11from ..util import FatalError, NotSupportedError
12
13
14class ESP32ROM(ESPLoader):
15    """Access class for ESP32 ROM bootloader"""
16
17    CHIP_NAME = "ESP32"
18    IMAGE_CHIP_ID = 0
19    IS_STUB = False
20
21    CHIP_DETECT_MAGIC_VALUE = [0x00F01D83]
22
23    IROM_MAP_START = 0x400D0000
24    IROM_MAP_END = 0x40400000
25
26    DROM_MAP_START = 0x3F400000
27    DROM_MAP_END = 0x3F800000
28
29    # ESP32 uses a 4 byte status reply
30    STATUS_BYTES_LENGTH = 4
31
32    SPI_REG_BASE = 0x3FF42000
33    SPI_USR_OFFS = 0x1C
34    SPI_USR1_OFFS = 0x20
35    SPI_USR2_OFFS = 0x24
36    SPI_MOSI_DLEN_OFFS = 0x28
37    SPI_MISO_DLEN_OFFS = 0x2C
38    EFUSE_RD_REG_BASE = 0x3FF5A000
39
40    EFUSE_BLK0_RDATA3_REG_OFFS = EFUSE_RD_REG_BASE + 0x00C
41    EFUSE_BLK0_RDATA5_REG_OFFS = EFUSE_RD_REG_BASE + 0x014
42
43    EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT_REG = EFUSE_RD_REG_BASE + 0x18
44    EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT = 1 << 7  # EFUSE_RD_DISABLE_DL_ENCRYPT
45
46    EFUSE_SPI_BOOT_CRYPT_CNT_REG = EFUSE_RD_REG_BASE  # EFUSE_BLK0_WDATA0_REG
47    EFUSE_SPI_BOOT_CRYPT_CNT_MASK = 0x7F << 20  # EFUSE_FLASH_CRYPT_CNT
48
49    EFUSE_RD_ABS_DONE_REG = EFUSE_RD_REG_BASE + 0x018
50    EFUSE_RD_ABS_DONE_0_MASK = 1 << 4
51    EFUSE_RD_ABS_DONE_1_MASK = 1 << 5
52
53    EFUSE_VDD_SPI_REG = EFUSE_RD_REG_BASE + 0x10
54    VDD_SPI_XPD = 1 << 14  # XPD_SDIO_REG
55    VDD_SPI_TIEH = 1 << 15  # XPD_SDIO_TIEH
56    VDD_SPI_FORCE = 1 << 16  # XPD_SDIO_FORCE
57
58    DR_REG_SYSCON_BASE = 0x3FF66000
59    APB_CTL_DATE_ADDR = DR_REG_SYSCON_BASE + 0x7C
60    APB_CTL_DATE_V = 0x1
61    APB_CTL_DATE_S = 31
62
63    SPI_W0_OFFS = 0x80
64
65    UART_CLKDIV_REG = 0x3FF40014
66
67    XTAL_CLK_DIVIDER = 1
68
69    RTCCALICFG1 = 0x3FF5F06C
70    TIMERS_RTC_CALI_VALUE = 0x01FFFFFF
71    TIMERS_RTC_CALI_VALUE_S = 7
72
73    GPIO_STRAP_REG = 0x3FF44038
74    GPIO_STRAP_VDDSPI_MASK = 1 << 5  # GPIO_STRAP_VDDSDIO
75
76    RTC_CNTL_SDIO_CONF_REG = 0x3FF48074
77    RTC_CNTL_XPD_SDIO_REG = 1 << 31
78    RTC_CNTL_DREFH_SDIO_M = 3 << 29
79    RTC_CNTL_DREFM_SDIO_M = 3 << 27
80    RTC_CNTL_DREFL_SDIO_M = 3 << 25
81    RTC_CNTL_SDIO_FORCE = 1 << 22
82    RTC_CNTL_SDIO_PD_EN = 1 << 21
83
84    FLASH_SIZES = {
85        "1MB": 0x00,
86        "2MB": 0x10,
87        "4MB": 0x20,
88        "8MB": 0x30,
89        "16MB": 0x40,
90        "32MB": 0x50,
91        "64MB": 0x60,
92        "128MB": 0x70,
93    }
94
95    FLASH_FREQUENCY = {
96        "80m": 0xF,
97        "40m": 0x0,
98        "26m": 0x1,
99        "20m": 0x2,
100    }
101
102    BOOTLOADER_FLASH_OFFSET = 0x1000
103
104    OVERRIDE_VDDSDIO_CHOICES = ["1.8V", "1.9V", "OFF"]
105
106    MEMORY_MAP = [
107        [0x00000000, 0x00010000, "PADDING"],
108        [0x3F400000, 0x3F800000, "DROM"],
109        [0x3F800000, 0x3FC00000, "EXTRAM_DATA"],
110        [0x3FF80000, 0x3FF82000, "RTC_DRAM"],
111        [0x3FF90000, 0x40000000, "BYTE_ACCESSIBLE"],
112        [0x3FFAE000, 0x40000000, "DRAM"],
113        [0x3FFE0000, 0x3FFFFFFC, "DIRAM_DRAM"],
114        [0x40000000, 0x40070000, "IROM"],
115        [0x40070000, 0x40078000, "CACHE_PRO"],
116        [0x40078000, 0x40080000, "CACHE_APP"],
117        [0x40080000, 0x400A0000, "IRAM"],
118        [0x400A0000, 0x400BFFFC, "DIRAM_IRAM"],
119        [0x400C0000, 0x400C2000, "RTC_IRAM"],
120        [0x400D0000, 0x40400000, "IROM"],
121        [0x50000000, 0x50002000, "RTC_DATA"],
122    ]
123
124    FLASH_ENCRYPTED_WRITE_ALIGN = 32
125
126    UF2_FAMILY_ID = 0x1C5F21B0
127
128    KEY_PURPOSES: Dict[int, str] = {}
129
130    """ Try to read the BLOCK1 (encryption key) and check if it is valid """
131
132    def is_flash_encryption_key_valid(self):
133        """Bit 0 of efuse_rd_disable[3:0] is mapped to BLOCK1
134        this bit is at position 16 in EFUSE_BLK0_RDATA0_REG"""
135        word0 = self.read_efuse(0)
136        rd_disable = (word0 >> 16) & 0x1
137
138        # reading of BLOCK1 is NOT ALLOWED so we assume valid key is programmed
139        if rd_disable:
140            return True
141        else:
142            # reading of BLOCK1 is ALLOWED so we will read and verify for non-zero.
143            # When ESP32 has not generated AES/encryption key in BLOCK1,
144            # the contents will be readable and 0.
145            # If the flash encryption is enabled it is expected to have a valid
146            # non-zero key. We break out on first occurrence of non-zero value
147            key_word = [0] * 7
148            for i in range(len(key_word)):
149                key_word[i] = self.read_efuse(14 + i)
150                # key is non-zero so break & return
151                if key_word[i] != 0:
152                    return True
153            return False
154
155    def get_flash_crypt_config(self):
156        """For flash encryption related commands we need to make sure
157        user has programmed all the relevant efuse correctly so before
158        writing encrypted write_flash_encrypt esptool will verify the values
159        of flash_crypt_config to be non zero if they are not read
160        protected. If the values are zero a warning will be printed
161
162        bit 3 in efuse_rd_disable[3:0] is mapped to flash_crypt_config
163        this bit is at position 19 in EFUSE_BLK0_RDATA0_REG"""
164        word0 = self.read_efuse(0)
165        rd_disable = (word0 >> 19) & 0x1
166
167        if rd_disable == 0:
168            """we can read the flash_crypt_config efuse value
169            so go & read it (EFUSE_BLK0_RDATA5_REG[31:28])"""
170            word5 = self.read_efuse(5)
171            word5 = (word5 >> 28) & 0xF
172            return word5
173        else:
174            # if read of the efuse is disabled we assume it is set correctly
175            return 0xF
176
177    def get_encrypted_download_disabled(self):
178        return (
179            self.read_reg(self.EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT_REG)
180            & self.EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT
181        )
182
183    def get_flash_encryption_enabled(self):
184        flash_crypt_cnt = (
185            self.read_reg(self.EFUSE_SPI_BOOT_CRYPT_CNT_REG)
186            & self.EFUSE_SPI_BOOT_CRYPT_CNT_MASK
187        )
188        # Flash encryption enabled when odd number of bits are set
189        return bin(flash_crypt_cnt).count("1") & 1 != 0
190
191    def get_secure_boot_enabled(self):
192        efuses = self.read_reg(self.EFUSE_RD_ABS_DONE_REG)
193        rev = self.get_chip_revision()
194        return efuses & self.EFUSE_RD_ABS_DONE_0_MASK or (
195            rev >= 300 and efuses & self.EFUSE_RD_ABS_DONE_1_MASK
196        )
197
198    def get_pkg_version(self):
199        word3 = self.read_efuse(3)
200        pkg_version = (word3 >> 9) & 0x07
201        pkg_version += ((word3 >> 2) & 0x1) << 3
202        return pkg_version
203
204    def get_chip_revision(self):
205        return self.get_major_chip_version() * 100 + self.get_minor_chip_version()
206
207    def get_minor_chip_version(self):
208        return (self.read_efuse(5) >> 24) & 0x3
209
210    def get_major_chip_version(self):
211        rev_bit0 = (self.read_efuse(3) >> 15) & 0x1
212        rev_bit1 = (self.read_efuse(5) >> 20) & 0x1
213        apb_ctl_date = self.read_reg(self.APB_CTL_DATE_ADDR)
214        rev_bit2 = (apb_ctl_date >> self.APB_CTL_DATE_S) & self.APB_CTL_DATE_V
215        combine_value = (rev_bit2 << 2) | (rev_bit1 << 1) | rev_bit0
216
217        revision = {
218            0: 0,
219            1: 1,
220            3: 2,
221            7: 3,
222        }.get(combine_value, 0)
223        return revision
224
225    def get_chip_description(self):
226        pkg_version = self.get_pkg_version()
227        major_rev = self.get_major_chip_version()
228        minor_rev = self.get_minor_chip_version()
229        rev3 = major_rev == 3
230        sc = self.read_efuse(3) & (1 << 0)  # single core, CHIP_VER DIS_APP_CPU
231
232        chip_name = {
233            0: "ESP32-S0WDQ6" if sc else "ESP32-D0WDQ6-V3" if rev3 else "ESP32-D0WDQ6",
234            1: "ESP32-S0WD" if sc else "ESP32-D0WD-V3" if rev3 else "ESP32-D0WD",
235            2: "ESP32-D2WD",
236            4: "ESP32-U4WDH",
237            5: "ESP32-PICO-V3" if rev3 else "ESP32-PICO-D4",
238            6: "ESP32-PICO-V3-02",
239            7: "ESP32-D0WDR2-V3",
240        }.get(pkg_version, "unknown ESP32")
241
242        return f"{chip_name} (revision v{major_rev}.{minor_rev})"
243
244    def get_chip_features(self):
245        features = ["WiFi"]
246        word3 = self.read_efuse(3)
247
248        # names of variables in this section are lowercase
249        #  versions of EFUSE names as documented in TRM and
250        # ESP-IDF efuse_reg.h
251
252        chip_ver_dis_bt = word3 & (1 << 1)
253        if chip_ver_dis_bt == 0:
254            features += ["BT"]
255
256        chip_ver_dis_app_cpu = word3 & (1 << 0)
257        if chip_ver_dis_app_cpu:
258            features += ["Single Core"]
259        else:
260            features += ["Dual Core"]
261
262        chip_cpu_freq_rated = word3 & (1 << 13)
263        if chip_cpu_freq_rated:
264            chip_cpu_freq_low = word3 & (1 << 12)
265            if chip_cpu_freq_low:
266                features += ["160MHz"]
267            else:
268                features += ["240MHz"]
269
270        pkg_version = self.get_pkg_version()
271        if pkg_version in [2, 4, 5, 6]:
272            features += ["Embedded Flash"]
273
274        if pkg_version == 6:
275            features += ["Embedded PSRAM"]
276
277        word4 = self.read_efuse(4)
278        adc_vref = (word4 >> 8) & 0x1F
279        if adc_vref:
280            features += ["VRef calibration in efuse"]
281
282        blk3_part_res = word3 >> 14 & 0x1
283        if blk3_part_res:
284            features += ["BLK3 partially reserved"]
285
286        word6 = self.read_efuse(6)
287        coding_scheme = word6 & 0x3
288        features += [
289            "Coding Scheme %s"
290            % {
291                0: "None",
292                1: "3/4",
293                2: "Repeat (UNSUPPORTED)",
294                3: "None (may contain encoding data)",
295            }[coding_scheme]
296        ]
297
298        return features
299
300    def get_chip_spi_pads(self):
301        """Read chip spi pad config
302        return: clk, q, d, hd, cd
303        """
304        efuse_blk0_rdata5 = self.read_reg(self.EFUSE_BLK0_RDATA5_REG_OFFS)
305        spi_pad_clk = efuse_blk0_rdata5 & 0x1F
306        spi_pad_q = (efuse_blk0_rdata5 >> 5) & 0x1F
307        spi_pad_d = (efuse_blk0_rdata5 >> 10) & 0x1F
308        spi_pad_cs = (efuse_blk0_rdata5 >> 15) & 0x1F
309
310        efuse_blk0_rdata3_reg = self.read_reg(self.EFUSE_BLK0_RDATA3_REG_OFFS)
311        spi_pad_hd = (efuse_blk0_rdata3_reg >> 4) & 0x1F
312        return spi_pad_clk, spi_pad_q, spi_pad_d, spi_pad_hd, spi_pad_cs
313
314    def read_efuse(self, n):
315        """Read the nth word of the ESP3x EFUSE region."""
316        return self.read_reg(self.EFUSE_RD_REG_BASE + (4 * n))
317
318    def chip_id(self):
319        raise NotSupportedError(self, "Function chip_id")
320
321    def read_mac(self, mac_type="BASE_MAC"):
322        """Read MAC from EFUSE region"""
323        if mac_type != "BASE_MAC":
324            return None
325        words = [self.read_efuse(2), self.read_efuse(1)]
326        bitstring = struct.pack(">II", *words)
327        bitstring = bitstring[2:8]  # trim the 2 byte CRC
328        return tuple(bitstring)
329
330    def get_erase_size(self, offset, size):
331        return size
332
333    def _get_efuse_flash_voltage(self) -> Optional[str]:
334        efuse = self.read_reg(self.EFUSE_VDD_SPI_REG)
335        # check efuse setting
336        if efuse & (self.VDD_SPI_FORCE | self.VDD_SPI_XPD | self.VDD_SPI_TIEH):
337            return "3.3V"
338        elif efuse & (self.VDD_SPI_FORCE | self.VDD_SPI_XPD):
339            return "1.8V"
340        elif efuse & self.VDD_SPI_FORCE:
341            return "OFF"
342        return None
343
344    def _get_rtc_cntl_flash_voltage(self) -> Optional[str]:
345        reg = self.read_reg(self.RTC_CNTL_SDIO_CONF_REG)
346        # check if override is set in RTC_CNTL_SDIO_CONF_REG
347        if reg & self.RTC_CNTL_SDIO_FORCE:
348            if reg & self.RTC_CNTL_DREFH_SDIO_M:
349                return "1.9V"
350            elif reg & self.RTC_CNTL_XPD_SDIO_REG:
351                return "1.8V"
352            else:
353                return "OFF"
354        return None
355
356    def get_flash_voltage(self):
357        """Get flash voltage setting and print it to the console."""
358        voltage = self._get_rtc_cntl_flash_voltage()
359        source = "RTC_CNTL"
360        if not voltage:
361            voltage = self._get_efuse_flash_voltage()
362            source = "eFuse"
363        if not voltage:
364            strap_reg = self.read_reg(self.GPIO_STRAP_REG)
365            strap_reg &= self.GPIO_STRAP_VDDSPI_MASK
366            voltage = "1.8V" if strap_reg else "3.3V"
367            source = "a strapping pin"
368        print(f"Flash voltage set by {source} to {voltage}")
369
370    def override_vddsdio(self, new_voltage):
371        new_voltage = new_voltage.upper()
372        if new_voltage not in self.OVERRIDE_VDDSDIO_CHOICES:
373            raise FatalError(
374                f"The only accepted VDDSDIO overrides are {', '.join(self.OVERRIDE_VDDSDIO_CHOICES)}"
375            )
376        # RTC_CNTL_SDIO_TIEH is not used here, setting TIEH=1 would set 3.3V output,
377        # not safe for esptool.py to do
378
379        reg_val = self.RTC_CNTL_SDIO_FORCE  # override efuse setting
380        reg_val |= self.RTC_CNTL_SDIO_PD_EN
381        if new_voltage != "OFF":
382            reg_val |= self.RTC_CNTL_XPD_SDIO_REG  # enable internal LDO
383        if new_voltage == "1.9V":
384            reg_val |= (
385                self.RTC_CNTL_DREFH_SDIO_M
386                | self.RTC_CNTL_DREFM_SDIO_M
387                | self.RTC_CNTL_DREFL_SDIO_M
388            )  # boost voltage
389        self.write_reg(self.RTC_CNTL_SDIO_CONF_REG, reg_val)
390        print("VDDSDIO regulator set to %s" % new_voltage)
391
392    def read_flash_slow(self, offset, length, progress_fn):
393        BLOCK_LEN = 64  # ROM read limit per command (this limit is why it's so slow)
394
395        data = b""
396        while len(data) < length:
397            block_len = min(BLOCK_LEN, length - len(data))
398            try:
399                r = self.check_command(
400                    "read flash block",
401                    self.ESP_READ_FLASH_SLOW,
402                    struct.pack("<II", offset + len(data), block_len),
403                )
404            except FatalError:
405                print(
406                    "Hint: Consider specifying flash size using '--flash_size' argument"
407                )
408                raise
409            if len(r) < block_len:
410                raise FatalError(
411                    "Expected %d byte block, got %d bytes. Serial errors?"
412                    % (block_len, len(r))
413                )
414            # command always returns 64 byte buffer,
415            # regardless of how many bytes were actually read from flash
416            data += r[:block_len]
417            if progress_fn and (len(data) % 1024 == 0 or len(data) == length):
418                progress_fn(len(data), length)
419        return data
420
421    def get_rom_cal_crystal_freq(self):
422        """
423        Get the crystal frequency calculated by the ROM
424        """
425        # - Simulate the calculation in the ROM to get the XTAL frequency
426        #   calculated by the ROM
427
428        cali_val = (
429            self.read_reg(self.RTCCALICFG1) >> self.TIMERS_RTC_CALI_VALUE_S
430        ) & self.TIMERS_RTC_CALI_VALUE
431        clk_8M_freq = self.read_efuse(4) & (0xFF)  # EFUSE_RD_CK8M_FREQ
432        rom_calculated_freq = cali_val * 15625 * clk_8M_freq / 40
433        return rom_calculated_freq
434
435    def change_baud(self, baud):
436        assert self.CHIP_NAME == "ESP32", "This workaround should only apply to ESP32"
437        # It's a workaround to avoid esp32 CK_8M frequency drift.
438        rom_calculated_freq = self.get_rom_cal_crystal_freq()
439        valid_freq = 40000000 if rom_calculated_freq > 33000000 else 26000000
440        false_rom_baud = int(baud * rom_calculated_freq // valid_freq)
441
442        print(f"Changing baud rate to {baud}")
443        self.command(self.ESP_CHANGE_BAUDRATE, struct.pack("<II", false_rom_baud, 0))
444        print("Changed.")
445        self._set_port_baudrate(baud)
446        time.sleep(0.05)  # get rid of garbage sent during baud rate change
447        self.flush_input()
448
449    def check_spi_connection(self, spi_connection):
450        # Pins 30, 31 do not exist
451        if not set(spi_connection).issubset(set(range(0, 30)) | set((32, 33))):
452            raise FatalError("SPI Pin numbers must be in the range 0-29, 32, or 33.")
453
454
455class ESP32StubLoader(ESP32ROM):
456    """Access class for ESP32 stub loader, runs on top of ROM."""
457
458    FLASH_WRITE_SIZE = 0x4000  # matches MAX_WRITE_BLOCK in stub_loader.c
459    STATUS_BYTES_LENGTH = 2  # same as ESP8266, different to ESP32 ROM
460    IS_STUB = True
461
462    def __init__(self, rom_loader):
463        self.secure_download_mode = rom_loader.secure_download_mode
464        self._port = rom_loader._port
465        self._trace_enabled = rom_loader._trace_enabled
466        self.cache = rom_loader.cache
467        self.flush_input()  # resets _slip_reader
468
469    def change_baud(self, baud):
470        ESPLoader.change_baud(self, baud)
471
472
473ESP32ROM.STUB_CLASS = ESP32StubLoader
474