diff --git a/src/esploader.ts b/src/esploader.ts index 37b7392d..fcfe46a4 100644 --- a/src/esploader.ts +++ b/src/esploader.ts @@ -2,7 +2,7 @@ import { ESPError } from "./error.js"; import { Data, deflate, Inflate } from "pako"; import { Transport, SerialOptions } from "./webserial.js"; import { ROM } from "./targets/rom.js"; -import { ClassicReset, ResetStrategy, UsbJtagSerialReset } from "./reset.js"; +import { ClassicReset, HardReset, ResetStrategy, UsbJtagSerialReset } from "./reset.js"; import { getStubJsonByChipName } from "./stubFlasher.js"; /* global SerialPort */ @@ -1542,11 +1542,11 @@ export class ESPLoader { /** * Perform a chip hard reset by setting RTS to LOW and then HIGH. + * @param {boolean} usesUsb Is the chip using USB */ - async hardReset() { - await this.transport.setRTS(true); // EN->LOW - await this._sleep(100); - await this.transport.setRTS(false); + async hardReset(usesUsb = false) { + const hardReset = new HardReset(this.transport, usesUsb); // TODO add usbOTGLogic + await hardReset.reset(); } /** diff --git a/src/reset.ts b/src/reset.ts index b413595b..5e96343e 100644 --- a/src/reset.ts +++ b/src/reset.ts @@ -116,6 +116,7 @@ export class HardReset implements ResetStrategy { } async reset() { + await this.transport.setRTS(true); if (this.usingUsbOtg) { await sleep(200); await this.transport.setRTS(false); diff --git a/src/targets/esp32c2.ts b/src/targets/esp32c2.ts index 3f927ad4..65140a04 100644 --- a/src/targets/esp32c2.ts +++ b/src/targets/esp32c2.ts @@ -30,6 +30,12 @@ export class ESP32C2ROM extends ESP32C3ROM { public SPI_MISO_DLEN_OFFS = 0x28; public SPI_W0_OFFS = 0x58; + public RTCCNTL_BASE_REG = 0x60008000; + public RTC_CNTL_WDTCONFIG0_REG = this.RTCCNTL_BASE_REG + 0x0084; + public RTC_CNTL_WDTCONFIG1_REG = this.RTCCNTL_BASE_REG + 0x0088; + public RTC_CNTL_WDTWPROTECT_REG = this.RTCCNTL_BASE_REG + 0x009c; + public RTC_CNTL_WDT_WKEY = 0x50d83aa1; + public async getPkgVersion(loader: ESPLoader): Promise { const numWord = 1; const block1Addr = this.EFUSE_BASE + 0x040; @@ -61,7 +67,7 @@ export class ESP32C2ROM extends ESP32C3ROM { return desc; } - public async getChipFeatures(loader: ESPLoader) { + public async getChipFeatures() { return ["Wi-Fi", "BLE"]; } @@ -123,4 +129,8 @@ export class ESP32C2ROM extends ESP32C3ROM { public getEraseSize(offset: number, size: number) { return size; } + + public async hardReset(loader: ESPLoader) { + return await loader.hardReset(); + } } diff --git a/src/targets/esp32c3.ts b/src/targets/esp32c3.ts index b9752023..55bad62b 100644 --- a/src/targets/esp32c3.ts +++ b/src/targets/esp32c3.ts @@ -6,10 +6,11 @@ export class ESP32C3ROM extends ROM { public IMAGE_CHIP_ID = 5; public EFUSE_BASE = 0x60008800; public MAC_EFUSE_REG = this.EFUSE_BASE + 0x044; - public UART_CLKDIV_REG = 0x3ff40014; public UART_CLKDIV_MASK = 0xfffff; public UART_DATE_REG_ADDR = 0x6000007c; + public CHIP_DETECT_MAGIC_VALUE = [0x6921506f, 0x1b31506f, 0x4881606f, 0x4361606f]; + public FLASH_WRITE_SIZE = 0x400; public BOOTLOADER_FLASH_OFFSET = 0; @@ -29,10 +30,41 @@ export class ESP32C3ROM extends ROM { public SPI_MISO_DLEN_OFFS = 0x28; public SPI_W0_OFFS = 0x58; + public RTCCNTL_BASE_REG = 0x60008000; + public RTC_CNTL_SWD_CONF_REG = this.RTCCNTL_BASE_REG + 0x00ac; + public RTC_CNTL_SWD_AUTO_FEED_EN = 1 << 31; + public RTC_CNTL_SWD_WPROTECT_REG = this.RTCCNTL_BASE_REG + 0x00b0; + public RTC_CNTL_SWD_WKEY = 0x8f1d312a; + + public RTC_CNTL_WDTCONFIG0_REG = this.RTCCNTL_BASE_REG + 0x0090; + public RTC_CNTL_WDTCONFIG1_REG = this.RTCCNTL_BASE_REG + 0x0094; + public RTC_CNTL_WDTWPROTECT_REG = this.RTCCNTL_BASE_REG + 0x00a8; + public RTC_CNTL_WDT_WKEY = 0x50d83aa1; + + public UART_CLKDIV_REG = 0x60000014; + public EFUSE_BLOCK1_ADDR = this.EFUSE_BASE + 0x044; + + public EFUSE_RD_REG_BASE = this.EFUSE_BASE + 0x030; // BLOCK0 read base address + + public EFUSE_PURPOSE_KEY0_REG = this.EFUSE_BASE + 0x34; + public EFUSE_PURPOSE_KEY0_SHIFT = 24; + public EFUSE_PURPOSE_KEY1_REG = this.EFUSE_BASE + 0x34; + public EFUSE_PURPOSE_KEY1_SHIFT = 28; + public EFUSE_PURPOSE_KEY2_REG = this.EFUSE_BASE + 0x38; + public EFUSE_PURPOSE_KEY2_SHIFT = 0; + public EFUSE_PURPOSE_KEY3_REG = this.EFUSE_BASE + 0x38; + public EFUSE_PURPOSE_KEY3_SHIFT = 4; + public EFUSE_PURPOSE_KEY4_REG = this.EFUSE_BASE + 0x38; + public EFUSE_PURPOSE_KEY4_SHIFT = 8; + public EFUSE_PURPOSE_KEY5_REG = this.EFUSE_BASE + 0x38; + public EFUSE_PURPOSE_KEY5_SHIFT = 12; + + public UARTDEV_BUF_NO = 0x3fcdf07c; // Variable in ROM .bss which indicates the port in use + public UARTDEV_BUF_NO_USB_JTAG_SERIAL = 3; // The above var when USB-JTAG/Serial is used + public async getPkgVersion(loader: ESPLoader): Promise { const numWord = 3; - const block1Addr = this.EFUSE_BASE + 0x044; - const addr = block1Addr + 4 * numWord; + const addr = this.EFUSE_BLOCK1_ADDR + 4 * numWord; const word3 = await loader.readReg(addr); const pkgVersion = (word3 >> 21) & 0x07; return pkgVersion; @@ -47,17 +79,30 @@ export class ESP32C3ROM extends ROM { return ret; } + public async getMajorChipVersion(loader: ESPLoader) { + const numWord = 5; + return ((await loader.readReg(this.EFUSE_BLOCK1_ADDR + 4 * numWord)) >> 24) & 0x03; + } + + public async getMinorChipVersion(loader: ESPLoader) { + const hiNumWord = 5; + const hi = ((await loader.readReg(this.EFUSE_BLOCK1_ADDR + 4 * hiNumWord)) >> 23) & 0x01; + const lowNumWord = 3; + const low = ((await loader.readReg(this.EFUSE_BLOCK1_ADDR + 4 * lowNumWord)) >> 18) & 0x07; + return (hi << 3) + low; + } + public async getChipDescription(loader: ESPLoader) { - let desc: string; - const pkgVer = await this.getPkgVersion(loader); - if (pkgVer === 0) { - desc = "ESP32-C3"; - } else { - desc = "unknown ESP32-C3"; - } - const chip_rev = await this.getChipRevision(loader); - desc += " (revision " + chip_rev + ")"; - return desc; + const chipDesc: { [key: number]: string } = { + 0: "ESP32-C3 (QFN32)", + 1: "ESP8685 (QFN28)", + 2: "ESP32-C3 AZ (QFN32)", + 3: "ESP8686 (QFN24)", + }; + const chipIndex = await this.getPkgVersion(loader); + const majorRev = await this.getMajorChipVersion(loader); + const minorRev = await this.getMinorChipVersion(loader); + return `${chipDesc[chipIndex] || "unknown ESP32-C3"} (revision v${majorRev}.${minorRev})`; } public async getFlashCap(loader: ESPLoader): Promise { @@ -71,8 +116,7 @@ export class ESP32C3ROM extends ROM { public async getFlashVendor(loader: ESPLoader): Promise { const numWord = 4; - const block1Addr = this.EFUSE_BASE + 0x044; - const addr = block1Addr + 4 * numWord; + const addr = this.EFUSE_BLOCK1_ADDR + 4 * numWord; const registerValue = await loader.readReg(addr); const vendorId = (registerValue >> 0) & 0x07; const vendorMap: { [key: number]: string } = { @@ -105,7 +149,7 @@ export class ESP32C3ROM extends ROM { return features; } - public async getCrystalFreq(loader: ESPLoader) { + public async getCrystalFreq(loader?: ESPLoader) { return 40; } @@ -145,4 +189,25 @@ export class ESP32C3ROM extends ROM { public getEraseSize(offset: number, size: number) { return size; } + + public async useUsbJTAGSerial(loader: ESPLoader) { + const reg = (await loader.readReg(this.UARTDEV_BUF_NO)) & 0xff; + return this.UARTDEV_BUF_NO_USB_JTAG_SERIAL === reg; + } + + public async rtcWdtReset(loader: ESPLoader) { + await loader.writeReg(this.RTC_CNTL_WDTWPROTECT_REG, this.RTC_CNTL_WDT_WKEY); // unlock + await loader.writeReg(this.RTC_CNTL_WDTCONFIG1_REG, 5000); // set WDT timeout + await loader.writeReg(this.RTC_CNTL_WDTCONFIG0_REG, (1 << 31) | (5 << 28) | (1 << 8) | 2); // enable WDT + await loader.writeReg(this.RTC_CNTL_WDTWPROTECT_REG, 0); // lock + } + + public async hardReset(loader: ESPLoader) { + const isUsingUsbJTAGSerial = await this.useUsbJTAGSerial(loader); + if (isUsingUsbJTAGSerial) { + await this.rtcWdtReset(loader); + } else { + loader.hardReset(); + } + } } diff --git a/src/targets/esp32c6.ts b/src/targets/esp32c6.ts index 1405c4c6..495b3003 100644 --- a/src/targets/esp32c6.ts +++ b/src/targets/esp32c6.ts @@ -1,7 +1,7 @@ import { ESPLoader } from "../esploader.js"; -import { ROM } from "./rom.js"; +import { ESP32C3ROM } from "./esp32c3.js"; -export class ESP32C6ROM extends ROM { +export class ESP32C6ROM extends ESP32C3ROM { public CHIP_NAME = "ESP32-C6"; public IMAGE_CHIP_ID = 13; public EFUSE_BASE = 0x600b0800; @@ -11,7 +11,7 @@ export class ESP32C6ROM extends ROM { public UART_DATE_REG_ADDR = 0x6000007c; public FLASH_WRITE_SIZE = 0x400; - public BOOTLOADER_FLASH_OFFSET = 0; + public BOOTLOADER_FLASH_OFFSET = 0x0; public FLASH_SIZES = { "1MB": 0x00, @@ -29,12 +29,65 @@ export class ESP32C6ROM extends ROM { public SPI_MISO_DLEN_OFFS = 0x28; public SPI_W0_OFFS = 0x58; + public UARTDEV_BUF_NO = 0x4087f580; // Variable in ROM .bss which indicates the port in use + public UARTDEV_BUF_NO_USB_JTAG_SERIAL = 3; // The above var when USB-JTAG/Serial is used + + public DR_REG_LP_WDT_BASE = 0x600b1c00; + + public RTC_CNTL_WDTCONFIG0_REG = this.DR_REG_LP_WDT_BASE + 0x0; // LP_WDT_RWDT_CONFIG0_REG + public RTC_CNTL_WDTCONFIG1_REG = this.DR_REG_LP_WDT_BASE + 0x0004; // LP_WDT_RWDT_CONFIG1_REG + public RTC_CNTL_WDTWPROTECT_REG = this.DR_REG_LP_WDT_BASE + 0x0018; // LP_WDT_RWDT_WPROTECT_REG + + public RTC_CNTL_SWD_CONF_REG = this.DR_REG_LP_WDT_BASE + 0x001c; // LP_WDT_SWD_CONFIG_REG + public RTC_CNTL_SWD_AUTO_FEED_EN = 1 << 18; + public RTC_CNTL_SWD_WPROTECT_REG = this.DR_REG_LP_WDT_BASE + 0x0020; // LP_WDT_SWD_WPROTECT_REG + public RTC_CNTL_SWD_WKEY = 0x50d83aa1; // LP_WDT_SWD_WKEY, same as WDT key in this case + + public IROM_MAP_START = 0x42000000; + public IROM_MAP_END = 0x42800000; + public DROM_MAP_START = 0x42800000; + public DROM_MAP_END = 0x43000000; + + // Magic value for ESP32C6 + CHIP_DETECT_MAGIC_VALUE = [0x2ce0806f]; + + EFUSE_BLOCK1_ADDR = this.EFUSE_BASE + 0x044; + + EFUSE_RD_REG_BASE = this.EFUSE_BASE + 0x030; // BLOCK0 read base address + + EFUSE_PURPOSE_KEY0_REG = this.EFUSE_BASE + 0x34; + EFUSE_PURPOSE_KEY0_SHIFT = 24; + EFUSE_PURPOSE_KEY1_REG = this.EFUSE_BASE + 0x34; + EFUSE_PURPOSE_KEY1_SHIFT = 28; + EFUSE_PURPOSE_KEY2_REG = this.EFUSE_BASE + 0x38; + EFUSE_PURPOSE_KEY2_SHIFT = 0; + EFUSE_PURPOSE_KEY3_REG = this.EFUSE_BASE + 0x38; + EFUSE_PURPOSE_KEY3_SHIFT = 4; + EFUSE_PURPOSE_KEY4_REG = this.EFUSE_BASE + 0x38; + EFUSE_PURPOSE_KEY4_SHIFT = 8; + EFUSE_PURPOSE_KEY5_REG = this.EFUSE_BASE + 0x38; + EFUSE_PURPOSE_KEY5_SHIFT = 12; + + EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT_REG = this.EFUSE_RD_REG_BASE; + EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT = 1 << 20; + + EFUSE_SPI_BOOT_CRYPT_CNT_REG = this.EFUSE_BASE + 0x034; + EFUSE_SPI_BOOT_CRYPT_CNT_MASK = 0x7 << 18; + + EFUSE_SECURE_BOOT_EN_REG = this.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; + public async getPkgVersion(loader: ESPLoader) { const numWord = 3; - const block1Addr = this.EFUSE_BASE + 0x044; - const addr = block1Addr + 4 * numWord; + const addr = this.EFUSE_BLOCK1_ADDR + 4 * numWord; const word3 = await loader.readReg(addr); - const pkgVersion = (word3 >> 21) & 0x07; + const pkgVersion = (word3 >> 24) & 0x07; return pkgVersion; } @@ -47,20 +100,30 @@ export class ESP32C6ROM extends ROM { return ret; } + public async getMinorChipVersion(loader: ESPLoader) { + const numWord = 3; + const regValue = await loader.readReg(this.EFUSE_BLOCK1_ADDR + 4 * numWord); + return (regValue >> 18) & 0x0f; + } + + public async getMajorChipVersion(loader: ESPLoader) { + const numWord = 3; + const regValue = await loader.readReg(this.EFUSE_BLOCK1_ADDR + 4 * numWord); + return (regValue >> 22) & 0x03; + } + public async getChipDescription(loader: ESPLoader) { - let desc: string; const pkgVer = await this.getPkgVersion(loader); - if (pkgVer === 0) { - desc = "ESP32-C6"; - } else { - desc = "unknown ESP32-C6"; - } - const chipRev = await this.getChipRevision(loader); - desc += " (revision " + chipRev + ")"; - return desc; + const chipDesc: { [key: number]: string } = { + 0: "ESP32-C6 (QFN40)", + 1: "ESP32-C6FH4 (QFN32)", + }; + const majorRev = await this.getMajorChipVersion(loader); + const minorRev = await this.getMinorChipVersion(loader); + return `${chipDesc[pkgVer] || "unknown ESP32-C6"} (revision v${majorRev}.${minorRev})`; } - public async getChipFeatures(loader: ESPLoader) { + public async getChipFeatures() { return ["Wi-Fi 6", "BT 5", "IEEE802.15.4"]; } diff --git a/src/targets/esp32c61.ts b/src/targets/esp32c61.ts index c42551a6..6f0b3139 100644 --- a/src/targets/esp32c61.ts +++ b/src/targets/esp32c61.ts @@ -107,7 +107,7 @@ export class ESP32C61ROM extends ESP32C6ROM { return `${desc} (revision v${majorRev}.${minorRev})`; } - public async getChipFeatures(loader: ESPLoader): Promise { + public async getChipFeatures(): Promise { return ["WiFi 6", "BT 5"]; } diff --git a/src/targets/esp32h2.ts b/src/targets/esp32h2.ts index ec6c5a0f..699151d6 100644 --- a/src/targets/esp32h2.ts +++ b/src/targets/esp32h2.ts @@ -1,47 +1,76 @@ import { ESPLoader } from "../esploader.js"; -import { ROM } from "./rom.js"; +import { ESP32C6ROM } from "./esp32c6.js"; -export class ESP32H2ROM extends ROM { +export class ESP32H2ROM extends ESP32C6ROM { public CHIP_NAME = "ESP32-H2"; public IMAGE_CHIP_ID = 16; - public EFUSE_BASE = 0x60008800; - public MAC_EFUSE_REG = this.EFUSE_BASE + 0x044; - public UART_CLKDIV_REG = 0x3ff40014; - public UART_CLKDIV_MASK = 0xfffff; - public UART_DATE_REG_ADDR = 0x6000007c; - - public FLASH_WRITE_SIZE = 0x400; - public BOOTLOADER_FLASH_OFFSET = 0x0; - - public FLASH_SIZES = { - "1MB": 0x00, - "2MB": 0x10, - "4MB": 0x20, - "8MB": 0x30, - "16MB": 0x40, + public CHIP_DETECT_MAGIC_VALUE = [0xd7b73e80]; + + public DR_REG_LP_WDT_BASE = 0x600b1c00; + public RTC_CNTL_WDTCONFIG0_REG = this.DR_REG_LP_WDT_BASE + 0x0; // LP_WDT_RWDT_CONFIG0_REG + public RTC_CNTL_WDTCONFIG1_REG = this.DR_REG_LP_WDT_BASE + 0x0004; // LP_WDT_RWDT_CONFIG1_REG + public RTC_CNTL_WDTWPROTECT_REG = this.DR_REG_LP_WDT_BASE + 0x001c; // LP_WDT_RWDT_WPROTECT_REG + + public RTC_CNTL_SWD_CONF_REG = this.DR_REG_LP_WDT_BASE + 0x0020; // LP_WDT_SWD_CONFIG_REG + public RTC_CNTL_SWD_AUTO_FEED_EN = 1 << 18; + public RTC_CNTL_SWD_WPROTECT_REG = this.DR_REG_LP_WDT_BASE + 0x0024; // LP_WDT_SWD_WPROTECT_REG + public RTC_CNTL_SWD_WKEY = 0x50d83aa1; // LP_WDT_SWD_WKEY, same as WDT key in this case + + public FLASH_FREQUENCY = { + "48m": 0xf, + "24m": 0x0, + "16m": 0x1, + "12m": 0x2, }; - public SPI_REG_BASE = 0x60002000; - public SPI_USR_OFFS = 0x18; - public SPI_USR1_OFFS = 0x1c; - public SPI_USR2_OFFS = 0x20; - public SPI_MOSI_DLEN_OFFS = 0x24; - public SPI_MISO_DLEN_OFFS = 0x28; - public SPI_W0_OFFS = 0x58; + public UF2_FAMILY_ID = 0x332726f6; - public USB_RAM_BLOCK = 0x800; - public UARTDEV_BUF_NO_USB = 3; - public UARTDEV_BUF_NO = 0x3fcef14c; + public EFUSE_MAX_KEY = 5; + public KEY_PURPOSES = { + 0: "USER/EMPTY", + 1: "ECDSA_KEY", + 2: "XTS_AES_256_KEY_1", + 3: "XTS_AES_256_KEY_2", + 4: "XTS_AES_128_KEY", + 5: "HMAC_DOWN_ALL", + 6: "HMAC_DOWN_JTAG", + 7: "HMAC_DOWN_DIGITAL_SIGNATURE", + 8: "HMAC_UP", + 9: "SECURE_BOOT_DIGEST0", + 10: "SECURE_BOOT_DIGEST1", + 11: "SECURE_BOOT_DIGEST2", + }; + + public async getPkgVersion(loader: ESPLoader) { + const numWord = 4; + return ((await loader.readReg(this.EFUSE_BLOCK1_ADDR + 4 * numWord)) >> 0) & 0x07; + } + + public async get_minorChipVersion(loader: ESPLoader) { + const numWord = 3; + return ((await loader.readReg(this.EFUSE_BLOCK1_ADDR + 4 * numWord)) >> 18) & 0x07; + } + + public async getMajorChipVersion(loader: ESPLoader) { + const numWord = 3; + return ((await loader.readReg(this.EFUSE_BLOCK1_ADDR + 4 * numWord)) >> 21) & 0x03; + } public async getChipDescription(loader: ESPLoader) { - return this.CHIP_NAME; + const chipDesc: { [key: number]: string } = { + 0: "ESP32-H2", + }; + const chipIndex = await this.getPkgVersion(loader); + const majorRev = await this.getMajorChipVersion(loader); + const minorRev = await this.getMinorChipVersion(loader); + return `${chipDesc[chipIndex] || "unknown ESP32-H2"} (revision v${majorRev}.${minorRev})`; } - public async getChipFeatures(loader: ESPLoader) { + public async getChipFeatures() { return ["BLE", "IEEE802.15.4"]; } - public async getCrystalFreq(loader: ESPLoader) { + public async getCrystalFreq() { // ESP32H2 XTAL is fixed to 32MHz return 32; } @@ -51,14 +80,6 @@ export class ESP32H2ROM extends ROM { return h.length === 1 ? "0" + h : h; } - public async postConnect(loader: ESPLoader) { - const bufNo = (await loader.readReg(this.UARTDEV_BUF_NO)) & 0xff; - loader.debug("In _post_connect " + bufNo); - if (bufNo == this.UARTDEV_BUF_NO_USB) { - loader.ESP_RAM_BLOCK = this.USB_RAM_BLOCK; - } - } - public async readMac(loader: ESPLoader) { let mac0 = await loader.readReg(this.MAC_EFUSE_REG); mac0 = mac0 >>> 0; @@ -90,4 +111,7 @@ export class ESP32H2ROM extends ROM { public getEraseSize(offset: number, size: number) { return size; } + public async hardReset(loader: ESPLoader) { + return await loader.hardReset(); + } } diff --git a/src/targets/esp32p4.ts b/src/targets/esp32p4.ts index a3a8b1f5..02fc34a1 100644 --- a/src/targets/esp32p4.ts +++ b/src/targets/esp32p4.ts @@ -60,6 +60,10 @@ export class ESP32P4ROM extends ESP32ROM { public FLASH_ENCRYPTED_WRITE_ALIGN = 16; + public UARTDEV_BUF_NO = 0x4ff3fec8; // Variable in ROM .bss which indicates the port in use + public UARTDEV_BUF_NO_USB_OTG = 5; // The above var when USB-OTG is used + public UARTDEV_BUF_NO_USB_JTAG_SERIAL = 6; // The above var when USB-JTAG/Serial is used + public MEMORY_MAP = [ [0x00000000, 0x00010000, "PADDING"], [0x40000000, 0x4c000000, "DROM"], @@ -93,11 +97,22 @@ export class ESP32P4ROM extends ESP32ROM { 12: "KM_INIT_KEY", }; + public DR_REG_LP_WDT_BASE = 0x50116000; + public RTC_CNTL_WDTCONFIG0_REG = this.DR_REG_LP_WDT_BASE + 0x0; // LP_WDT_CONFIG0_REG + public RTC_CNTL_WDTCONFIG1_REG = this.DR_REG_LP_WDT_BASE + 0x0004; // LP_WDT_CONFIG1_REG + public RTC_CNTL_WDTWPROTECT_REG = this.DR_REG_LP_WDT_BASE + 0x0018; // LP_WDT_WPROTECT_REG + public RTC_CNTL_WDT_WKEY = 0x50d83aa1; + + public RTC_CNTL_SWD_CONF_REG = this.DR_REG_LP_WDT_BASE + 0x001c; // RTC_WDT_SWD_CONFIG_REG + public RTC_CNTL_SWD_AUTO_FEED_EN = 1 << 18; + public RTC_CNTL_SWD_WPROTECT_REG = this.DR_REG_LP_WDT_BASE + 0x0020; // RTC_WDT_SWD_WPROTECT_REG + public RTC_CNTL_SWD_WKEY = 0x50d83aa1; // RTC_WDT_SWD_WKEY, same as WDT key in this case + public async getPkgVersion(loader: ESPLoader): Promise { const numWord = 2; const addr = this.EFUSE_BLOCK1_ADDR + 4 * numWord; const registerValue = await loader.readReg(addr); - return (registerValue >> 27) & 0x07; + return (registerValue >> 20) & 0x07; } public async getMinorChipVersion(loader: ESPLoader): Promise { @@ -122,15 +137,15 @@ export class ESP32P4ROM extends ESP32ROM { return `${chipName} (revision v${majorRev}.${minorRev})`; } - public async getChipFeatures(loader: ESPLoader): Promise { + public async getChipFeatures(): Promise { return ["High-Performance MCU"]; } - public async getCrystalFreq(loader: ESPLoader): Promise { + public async getCrystalFreq(): Promise { return 40; // ESP32P4 XTAL is fixed to 40MHz } - public async getFlashVoltage(loader: ESPLoader) { + public async getFlashVoltage() { return; } @@ -166,7 +181,7 @@ export class ESP32P4ROM extends ESP32ROM { ); } - public async getFlashCryptConfig(loader: ESPLoader) { + public async getFlashCryptConfig() { return; // doesn't exist on ESP32-P4 } @@ -212,4 +227,30 @@ export class ESP32P4ROM extends ESP32ROM { } return false; } + + public async usingUsbOtg(loader: ESPLoader) { + const uartNo = (await loader.readReg(this.UARTDEV_BUF_NO)) & 0xff; + return uartNo === this.UARTDEV_BUF_NO_USB_OTG; + } + + public async usingUsbJtagSerial(loader: ESPLoader) { + const uartNo = (await loader.readReg(this.UARTDEV_BUF_NO)) & 0xff; + return uartNo === this.UARTDEV_BUF_NO_USB_JTAG_SERIAL; + } + + public async rtcWdtReset(loader: ESPLoader) { + await loader.writeReg(this.RTC_CNTL_WDTWPROTECT_REG, this.RTC_CNTL_WDT_WKEY); // unlock + await loader.writeReg(this.RTC_CNTL_WDTCONFIG1_REG, 5000); // set WDT timeout + await loader.writeReg(this.RTC_CNTL_WDTCONFIG0_REG, (1 << 31) | (5 << 28) | (1 << 8) | 2); // enable WDT + await loader.writeReg(this.RTC_CNTL_WDTWPROTECT_REG, 0); // lock + } + + public async hardReset(loader: ESPLoader) { + const isUsingUsbJTAGSerial = await this.usingUsbJtagSerial(loader); + if (isUsingUsbJTAGSerial) { + await this.rtcWdtReset(loader); + } else { + loader.hardReset(); + } + } } diff --git a/src/targets/esp32s2.ts b/src/targets/esp32s2.ts index e4baffa7..17127b83 100644 --- a/src/targets/esp32s2.ts +++ b/src/targets/esp32s2.ts @@ -281,4 +281,28 @@ export class ESP32S2ROM extends ROM { loader.ESP_RAM_BLOCK = this.USB_RAM_BLOCK; } } + + public async rtcWdtReset(loader: ESPLoader) { + await loader.writeReg(this.RTC_CNTL_WDTWPROTECT_REG, this.RTC_CNTL_WDT_WKEY); // unlock + await loader.writeReg(this.RTC_CNTL_WDTCONFIG1_REG, 5000); // set WDT timeout + await loader.writeReg(this.RTC_CNTL_WDTCONFIG0_REG, (1 << 31) | (5 << 28) | (1 << 8) | 2); // enable WDT + await loader.writeReg(this.RTC_CNTL_WDTWPROTECT_REG, 0); // lock + } + + public async hardReset(loader: ESPLoader) { + const isUsingUsbOtg = await this.usingUsbOtg(loader); + if (isUsingUsbOtg) { + const strapReg = await loader.readReg(this.GPIO_STRAP_REG); + const forceDlReg = await loader.readReg(this.RTC_CNTL_OPTION1_REG); + if ( + (strapReg & this.GPIO_STRAP_SPI_BOOT_MASK) === 0 && + (forceDlReg & this.RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK) === 0 + ) { + // GPIO0 Low + await this.rtcWdtReset(loader); + } + } else { + loader.hardReset(); + } + } } diff --git a/src/targets/esp32s3.ts b/src/targets/esp32s3.ts index 97e3488b..0dacc120 100644 --- a/src/targets/esp32s3.ts +++ b/src/targets/esp32s3.ts @@ -5,9 +5,9 @@ export class ESP32S3ROM extends ROM { public CHIP_NAME = "ESP32-S3"; public IMAGE_CHIP_ID = 9; public EFUSE_BASE = 0x60007000; - public MAC_EFUSE_REG = this.EFUSE_BASE + 0x044; public EFUSE_BLOCK1_ADDR = this.EFUSE_BASE + 0x44; public EFUSE_BLOCK2_ADDR = this.EFUSE_BASE + 0x5c; + public MAC_EFUSE_REG = this.EFUSE_BASE + 0x044; public UART_CLKDIV_REG = 0x60000014; public UART_CLKDIV_MASK = 0xfffff; public UART_DATE_REG_ADDR = 0x60000080; @@ -33,7 +33,57 @@ export class ESP32S3ROM extends ROM { public USB_RAM_BLOCK = 0x800; public UARTDEV_BUF_NO_USB = 3; - public UARTDEV_BUF_NO = 0x3fcef14c; + public UARTDEV_BUF_NO = 0x3fcef14c; // Variable in ROM .bss which indicates the port in use + public UARTDEV_BUF_NO_USB_OTG = 3; // The above var when USB-OTG is used + public UARTDEV_BUF_NO_USB_JTAG_SERIAL = 4; // The above var when USB-JTAG/Serial is used + + public EFUSE_RD_REG_BASE = this.EFUSE_BASE + 0x030; // BLOCK0 read base address + + public EFUSE_PURPOSE_KEY0_REG = this.EFUSE_BASE + 0x34; + public EFUSE_PURPOSE_KEY0_SHIFT = 24; + public EFUSE_PURPOSE_KEY1_REG = this.EFUSE_BASE + 0x34; + public EFUSE_PURPOSE_KEY1_SHIFT = 28; + public EFUSE_PURPOSE_KEY2_REG = this.EFUSE_BASE + 0x38; + public EFUSE_PURPOSE_KEY2_SHIFT = 0; + public EFUSE_PURPOSE_KEY3_REG = this.EFUSE_BASE + 0x38; + public EFUSE_PURPOSE_KEY3_SHIFT = 4; + public EFUSE_PURPOSE_KEY4_REG = this.EFUSE_BASE + 0x38; + public EFUSE_PURPOSE_KEY4_SHIFT = 8; + public EFUSE_PURPOSE_KEY5_REG = this.EFUSE_BASE + 0x38; + public EFUSE_PURPOSE_KEY5_SHIFT = 12; + + public EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT_REG = this.EFUSE_RD_REG_BASE; + public EFUSE_DIS_DOWNLOAD_MANUAL_ENCRYPT = 1 << 20; + + public EFUSE_SPI_BOOT_CRYPT_CNT_REG = this.EFUSE_BASE + 0x034; + public EFUSE_SPI_BOOT_CRYPT_CNT_MASK = 0x7 << 18; + + public EFUSE_SECURE_BOOT_EN_REG = this.EFUSE_BASE + 0x038; + public EFUSE_SECURE_BOOT_EN_MASK = 1 << 20; + + public EFUSE_RD_REPEAT_DATA3_REG = this.EFUSE_BASE + 0x3c; + public EFUSE_RD_REPEAT_DATA3_REG_FLASH_TYPE_MASK = 1 << 9; + + public PURPOSE_VAL_XTS_AES256_KEY_1 = 2; + public PURPOSE_VAL_XTS_AES256_KEY_2 = 3; + public PURPOSE_VAL_XTS_AES128_KEY = 4; + + public RTCCNTL_BASE_REG = 0x60008000; + public RTC_CNTL_SWD_CONF_REG = this.RTCCNTL_BASE_REG + 0x00b4; + public RTC_CNTL_SWD_AUTO_FEED_EN = 1 << 31; + public RTC_CNTL_SWD_WPROTECT_REG = this.RTCCNTL_BASE_REG + 0x00b8; + public RTC_CNTL_SWD_WKEY = 0x8f1d312a; + + public RTC_CNTL_WDTCONFIG0_REG = this.RTCCNTL_BASE_REG + 0x0098; + public RTC_CNTL_WDTCONFIG1_REG = this.RTCCNTL_BASE_REG + 0x009c; + public RTC_CNTL_WDTWPROTECT_REG = this.RTCCNTL_BASE_REG + 0x00b0; + public RTC_CNTL_WDT_WKEY = 0x50d83aa1; + + public GPIO_STRAP_REG = 0x60004038; + public GPIO_STRAP_SPI_BOOT_MASK = 1 << 3; // Not download mode + public GPIO_STRAP_VDDSPI_MASK = 1 << 4; + public RTC_CNTL_OPTION1_REG = 0x6000812c; + public RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK = 0x1; // Is download mode forced over USB? public async getChipDescription(loader: ESPLoader) { const majorRev = await this.getMajorChipVersion(loader); @@ -104,8 +154,7 @@ export class ESP32S3ROM extends ROM { public async getFlashCap(loader: ESPLoader): Promise { const numWord = 3; - const block1Addr = this.EFUSE_BASE + 0x044; - const addr = block1Addr + 4 * numWord; + const addr = this.EFUSE_BLOCK1_ADDR + 4 * numWord; const registerValue = await loader.readReg(addr); const flashCap = (registerValue >> 27) & 0x07; return flashCap; @@ -113,8 +162,7 @@ export class ESP32S3ROM extends ROM { public async getFlashVendor(loader: ESPLoader): Promise { const numWord = 4; - const block1Addr = this.EFUSE_BASE + 0x044; - const addr = block1Addr + 4 * numWord; + const addr = this.EFUSE_BLOCK1_ADDR + 4 * numWord; const registerValue = await loader.readReg(addr); const vendorId = (registerValue >> 0) & 0x07; const vendorMap: { [key: number]: string } = { @@ -129,17 +177,17 @@ export class ESP32S3ROM extends ROM { public async getPsramCap(loader: ESPLoader): Promise { const numWord = 4; - const block1Addr = this.EFUSE_BASE + 0x044; - const addr = block1Addr + 4 * numWord; + const addr = this.EFUSE_BLOCK1_ADDR + 4 * numWord; const registerValue = await loader.readReg(addr); const psramCap = (registerValue >> 3) & 0x03; - return psramCap; + const capHiBitNumWord = 5; + const psramCapHiBit = ((await loader.readReg(this.EFUSE_BLOCK1_ADDR + 4 * capHiBitNumWord)) >> 19) & 0x01; + return (psramCapHiBit << 2) | psramCap; } public async getPsramVendor(loader: ESPLoader): Promise { const numWord = 4; - const block1Addr = this.EFUSE_BASE + 0x044; - const addr = block1Addr + 4 * numWord; + const addr = this.EFUSE_BLOCK1_ADDR + 4 * numWord; const registerValue = await loader.readReg(addr); const vendorId = (registerValue >> 7) & 0x03; const vendorMap: { [key: number]: string } = { @@ -169,6 +217,8 @@ export class ESP32S3ROM extends ROM { 0: null, 1: "Embedded PSRAM 8MB", 2: "Embedded PSRAM 2MB", + 3: "Embedded PSRAM 16MB", + 4: "Embedded PSRAM 4MB", }; const psramCap = await this.getPsramCap(loader); const psramVendor = await this.getPsramVendor(loader); @@ -180,7 +230,7 @@ export class ESP32S3ROM extends ROM { return features; } - public async getCrystalFreq(loader: ESPLoader) { + public async getCrystalFreq() { return 40; } public _d2h(d: number) { @@ -227,4 +277,51 @@ export class ESP32S3ROM extends ROM { public getEraseSize(offset: number, size: number) { return size; } + + public async usingUsbOtg(loader: ESPLoader) { + const uartNo = (await loader.readReg(this.UARTDEV_BUF_NO)) & 0xff; + return uartNo === this.UARTDEV_BUF_NO_USB_OTG; + } + + public async useUsbJTAGSerial(loader: ESPLoader) { + const reg = (await loader.readReg(this.UARTDEV_BUF_NO)) & 0xff; // uart_no + return this.UARTDEV_BUF_NO_USB_JTAG_SERIAL === reg; + } + + public async rtcWdtReset(loader: ESPLoader) { + await loader.writeReg(this.RTC_CNTL_WDTWPROTECT_REG, this.RTC_CNTL_WDT_WKEY); // unlock + await loader.writeReg(this.RTC_CNTL_WDTCONFIG1_REG, 5000); // set WDT timeout + await loader.writeReg(this.RTC_CNTL_WDTCONFIG0_REG, (1 << 31) | (5 << 28) | (1 << 8) | 2); // enable WDT + await loader.writeReg(this.RTC_CNTL_WDTWPROTECT_REG, 0); // lock + } + + public async hardReset(loader: ESPLoader) { + try { + // Clear force download boot mode to avoid the chip being stuck in download mode after reset + await loader.writeReg(this.RTC_CNTL_OPTION1_REG, 0, this.RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK); + } catch (error) { + let msg = "Error while clearing force download boot mode"; + if (error instanceof Error) { + msg = error.message; + } else if (typeof error === "string") { + msg = error; + } + console.log(msg); + } + const isUsingUsbOtg = await this.usingUsbOtg(loader); + const isUsingUsbJTAGSerial = await this.useUsbJTAGSerial(loader); + if (isUsingUsbOtg || isUsingUsbJTAGSerial) { + const strapReg = await loader.readReg(this.GPIO_STRAP_REG); + const forceDlReg = await loader.readReg(this.RTC_CNTL_OPTION1_REG); + if ( + (strapReg & this.GPIO_STRAP_SPI_BOOT_MASK) === 0 && + (forceDlReg & this.RTC_CNTL_FORCE_DOWNLOAD_BOOT_MASK) === 0 + ) { + // GPIO0 Low + await this.rtcWdtReset(loader); + } + } else { + loader.hardReset(); + } + } }