Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func main() {
port := flag.String("port", "", "Serial port (e.g. /dev/ttyUSB0, COM3)")
baud := flag.Int("baud", 460800, "Flash baud rate")
offset := flag.String("offset", "0x0", "Flash offset for single binary mode")
chip := flag.String("chip", "auto", "Chip type: auto, esp8266, esp32, esp32s2, esp32s3, esp32c2, esp32c3, esp32c5, esp32c6, esp32h2")
chip := flag.String("chip", "auto", "Chip type: auto, esp8266, esp32, esp32s2, esp32s3, esp32c2, esp32c3, esp32c5, esp32c6, esp32h2, esp32p4-rev1")
noCompress := flag.Bool("no-compress", false, "Disable compression")
eraseAll := flag.Bool("erase-all", false, "Erase entire flash before writing")
flashMode := flag.String("fm", "keep", "Flash mode: keep, qio, qout, dio, dout")
Expand Down Expand Up @@ -232,6 +232,8 @@ func parseChipType(s string) espflasher.ChipType {
return espflasher.ChipESP32C6
case "esp32h2", "esp32-h2":
return espflasher.ChipESP32H2
case "esp32p4-rev1", "esp32-p4-rev1":
return espflasher.ChipESP32P4Rev1
default:
log.Fatalf("Unknown chip type: %s", s)
return espflasher.ChipAuto
Expand Down
22 changes: 13 additions & 9 deletions pkg/espflasher/chip.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const (
ChipESP32C5
ChipESP32C6
ChipESP32H2
ChipESP32P4Rev1
ChipAuto // Auto-detect chip type
)

Expand All @@ -39,6 +40,8 @@ func (c ChipType) String() string {
return "ESP32-C6"
case ChipESP32H2:
return "ESP32-H2"
case ChipESP32P4Rev1:
return "ESP32-P4-Rev1"
case ChipAuto:
return "Auto"
default:
Expand Down Expand Up @@ -130,15 +133,16 @@ const chipDetectMagicRegAddr uint32 = 0x40001000

// All known chip definitions.
var chipDefs = map[ChipType]*chipDef{
ChipESP8266: defESP8266,
ChipESP32: defESP32,
ChipESP32S2: defESP32S2,
ChipESP32S3: defESP32S3,
ChipESP32C2: defESP32C2,
ChipESP32C3: defESP32C3,
ChipESP32C5: defESP32C5,
ChipESP32C6: defESP32C6,
ChipESP32H2: defESP32H2,
ChipESP8266: defESP8266,
ChipESP32: defESP32,
ChipESP32S2: defESP32S2,
ChipESP32S3: defESP32S3,
ChipESP32C2: defESP32C2,
ChipESP32C3: defESP32C3,
ChipESP32C5: defESP32C5,
ChipESP32C6: defESP32C6,
ChipESP32H2: defESP32H2,
ChipESP32P4Rev1: defESP32P4Rev1,
}

// detectChipByMagic returns the chip definition matching the given magic value,
Expand Down
1 change: 1 addition & 0 deletions pkg/espflasher/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
// - ESP32-C5
// - ESP32-C6
// - ESP32-H2
// - ESP32-P4 (rev 1 / ECO2)
//
// # Quick Start
//
Expand Down
19 changes: 10 additions & 9 deletions pkg/espflasher/stub.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,16 @@ var stubFS embed.FS

// chipStubName maps each supported chip type to its stub JSON filename stem.
var chipStubName = map[ChipType]string{
ChipESP8266: "esp8266",
ChipESP32: "esp32",
ChipESP32S2: "esp32s2",
ChipESP32S3: "esp32s3",
ChipESP32C2: "esp32c2",
ChipESP32C3: "esp32c3",
ChipESP32C5: "esp32c5",
ChipESP32C6: "esp32c6",
ChipESP32H2: "esp32h2",
ChipESP8266: "esp8266",
ChipESP32: "esp32",
ChipESP32S2: "esp32s2",
ChipESP32S3: "esp32s3",
ChipESP32C2: "esp32c2",
ChipESP32C3: "esp32c3",
ChipESP32C5: "esp32c5",
ChipESP32C6: "esp32c6",
ChipESP32H2: "esp32h2",
ChipESP32P4Rev1: "esp32p4-rev1",
}

// stubJSON mirrors the JSON structure of the esptool stub flasher files.
Expand Down
8 changes: 8 additions & 0 deletions pkg/espflasher/stubs/esp32p4-rev1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"entry": 1341194240,
"text": "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",
"text_start": 1341194240,
"data": "ChLxT0yC9U+QA/FPkAPxT5AD8U+QA/FPkAPxT5AD8U+QA/FPkAPxT5AD8U+QA/FPkAPxT5AD8U+QA/FPkAPxT5AD8U+QA/FPkAPxT5AD8U+QA/FPkAPxT5AD8U+QA/FPkAPxT5AD8U+QA/FPkAPxT5AD8U+iCvFPrgrxT/oK8U8mC/FPsAvxT1oL8U+ECvFP8gvxT24M8U+UDPFPRArxT4IM8U9ECvFP+gzxTwoN8U8ODfFP+grxT2YN8U96DfFP",
"data_start": 1341533624,
"bss_start": 1341456384
}
80 changes: 80 additions & 0 deletions pkg/espflasher/target_esp32p4_rev1.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package espflasher

// ESP32-P4 Rev1 (ECO2, chip revision < 3.0) register addresses for USB
// interface detection and watchdog control.
// Reference: esptool/targets/esp32p4.py (P4-specific values) and
// esptool/targets/esp32.py (ESP32ROM base-class SPI defaults P4 inherits).
//
// UARTDEV_BUF_NO is revision-dependent in esptool:
// rev < 3.0 (ECO2, this target): 0x4FF3FEB0 + 24 = 0x4FF3FEC8
// rev >= 3.0 (production, future): 0x4FFBFEB0 + 24 = 0x4FFBFEC8
// The USB-JTAG/Serial sentinel is 6 on P4 (not 3 like C5/C6/H2).
const (
esp32p4Rev1UARTDevBufNo uint32 = 0x4FF3FEC8
esp32p4UARTDevBufNoUSBJTAGSerial uint32 = 6

esp32p4LPWDTConfig0 uint32 = 0x50116000
esp32p4LPWDTWProtect uint32 = 0x50116018
esp32p4LPWDTSWDConf uint32 = 0x5011601C
esp32p4LPWDTSWDWProtect uint32 = 0x50116020
)

// ESP32-P4 Rev1 target definition.
// Reference: https://github.com/espressif/esptool/blob/master/esptool/targets/esp32p4.py
// Production silicon (rev >= 3.0) uses a different UARTDEV_BUF_NO address and
// the esp32p4.json stub; it will land as a separate target when we have that hardware.

var defESP32P4Rev1 = &chipDef{
ChipType: ChipESP32P4Rev1,
Name: "ESP32-P4-Rev1",
ImageChipID: 18,
UsesMagicValue: false,

SPIRegBase: 0x5008D000,
SPIUSROffs: 0x18,
SPIUSR1Offs: 0x1C,
SPIUSR2Offs: 0x20,
SPIMOSIOffs: 0x24,
SPIMISOOffs: 0x98,
SPIW0Offs: 0x58,

SPIMISODLenOffs: 0x28,
SPIMOSIDLenOffs: 0x24,

SPIAddrRegMSB: false,

UARTDateReg: 0x500CA08C,
UARTClkDiv: 0x500CA014,
XTALClkDiv: 1,

BootloaderFlashOffset: 0x2000,

SupportsEncryptedFlash: true,
ROMHasCompressedFlash: true,
ROMHasChangeBaud: true,

FlashFrequency: map[string]byte{
"80m": 0xF,
"40m": 0x0,
"20m": 0x2,
},

FlashSizes: defaultFlashSizes(),

PostConnect: esp32p4Rev1PostConnect,
}

func esp32p4Rev1PostConnect(f *Flasher) error {
uartDev, err := f.ReadRegister(esp32p4Rev1UARTDevBufNo)
if err != nil {
return nil
}

if uartDev == esp32p4UARTDevBufNoUSBJTAGSerial {
f.usesUSB = true
f.logf("USB-JTAG/Serial interface detected (ESP32-P4 rev1), disabling watchdogs")
return disableWatchdogsLP(f, esp32p4LPWDTConfig0, esp32p4LPWDTWProtect, esp32p4LPWDTSWDConf, esp32p4LPWDTSWDWProtect)
}

return nil
}
71 changes: 71 additions & 0 deletions pkg/espflasher/target_esp32p4_rev1_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package espflasher

import (
"errors"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestESP32P4Rev1PostConnectUSBJTAG(t *testing.T) {
writeCount := 0
readCount := 0

mc := &mockConnection{
readRegFunc: func(addr uint32) (uint32, error) {
readCount++
if addr == esp32p4Rev1UARTDevBufNo {
return esp32p4UARTDevBufNoUSBJTAGSerial, nil
}
// Return 0 for SWD conf read
return 0, nil
},
writeRegFunc: func(addr, value, mask, delayUS uint32) error {
writeCount++
return nil
},
}
f := &Flasher{
conn: mc,
opts: &FlasherOptions{},
}

err := esp32p4Rev1PostConnect(f)
require.NoError(t, err)
assert.True(t, f.usesUSB, "usesUSB should be true for USB-JTAG/Serial")
assert.Greater(t, writeCount, 0, "should have written registers to disable watchdog")
}

func TestESP32P4Rev1PostConnectUART(t *testing.T) {
mc := &mockConnection{
readRegFunc: func(addr uint32) (uint32, error) {
return 0, nil // Not USB, return UART value
},
}
f := &Flasher{
conn: mc,
opts: &FlasherOptions{},
}

err := esp32p4Rev1PostConnect(f)
require.NoError(t, err)
assert.False(t, f.usesUSB, "usesUSB should be false for UART")
}

func TestESP32P4Rev1PostConnectSecureMode(t *testing.T) {
// Simulate read error (secure download mode)
mc := &mockConnection{
readRegFunc: func(addr uint32) (uint32, error) {
return 0, errors.New("register not readable") // Simulate unreadable register
},
}
f := &Flasher{
conn: mc,
opts: &FlasherOptions{},
}

err := esp32p4Rev1PostConnect(f)
require.NoError(t, err, "should gracefully handle read error")
assert.False(t, f.usesUSB, "should default to non-USB on read error")
}
1 change: 1 addition & 0 deletions tools/update-stubs.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ var chips = []string{
"esp32c5",
"esp32c6",
"esp32h2",
"esp32p4-rev1",
}

func main() {
Expand Down
Loading