diff --git a/.cargo/config.toml b/.cargo/config.toml index 0083c125..2dbe035c 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,3 +1,4 @@ [alias] xtask = "run --package xtask --" +xgenerate-efuse-fields = "run --package xtask --features=efuse-generator -- generate-efuse-fields" xrun = "run --package espflash --" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9c7b738f..8f38ce3b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -123,7 +123,7 @@ jobs: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - - run: cargo check -p xtask + - run: cargo check -p xtask --all-features # -------------------------------------------------------------------------- # Test diff --git a/.github/workflows/hil.yml b/.github/workflows/hil.yml index deddafc8..495af01b 100644 --- a/.github/workflows/hil.yml +++ b/.github/workflows/hil.yml @@ -119,4 +119,4 @@ jobs: echo "$PWD/xtask_app" >> "$GITHUB_PATH" - name: Run all tests - run: xtask run-tests --chip ${{ matrix.board.mcu }} -t 60 --no-build \ No newline at end of file + run: xtask run-tests --chip ${{ matrix.board.mcu }} -t 60 --no-build diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d59eee4..1ce7fe0d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,7 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed -- Corrected eFuse BLOCK0 definitions for ESP32-C2, ESP32-C3, and ESP32-S3 (#961) +- Corrected eFuse block address calculations. (#971) - Fixed Secure Download Mode detection on ESP32-P4 (#972) - Several fixes in `read_efuse` (#969) - Fixed a problem in detecting the app-descriptor for a project if `strip = true` is used (#975) diff --git a/Cargo.lock b/Cargo.lock index c0b9af85..1aa7b3b8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -903,6 +903,7 @@ dependencies = [ "miette", "nix 0.30.1", "object 0.37.3", + "reed-solomon", "regex", "serde", "serialport", @@ -1377,6 +1378,15 @@ dependencies = [ "web-time", ] +[[package]] +name = "indoc" +version = "2.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" +dependencies = [ + "rustversion", +] + [[package]] name = "io-kit-sys" version = "0.4.1" @@ -1564,6 +1574,15 @@ dependencies = [ "libc", ] +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + [[package]] name = "miette" version = "7.6.0" @@ -1876,6 +1895,67 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "pyo3" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37a6df7eab65fc7bee654a421404947e10a0f7085b6951bf2ea395f4659fb0cf" +dependencies = [ + "indoc", + "libc", + "memoffset", + "once_cell", + "portable-atomic", + "pyo3-build-config", + "pyo3-ffi", + "pyo3-macros", + "unindent", +] + +[[package]] +name = "pyo3-build-config" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f77d387774f6f6eec64a004eac0ed525aab7fa1966d94b42f743797b3e395afb" +dependencies = [ + "target-lexicon", +] + +[[package]] +name = "pyo3-ffi" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dd13844a4242793e02df3e2ec093f540d948299a6a77ea9ce7afd8623f542be" +dependencies = [ + "libc", + "pyo3-build-config", +] + +[[package]] +name = "pyo3-macros" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaf8f9f1108270b90d3676b8679586385430e5c0bb78bb5f043f95499c821a71" +dependencies = [ + "proc-macro2", + "pyo3-macros-backend", + "quote", + "syn", +] + +[[package]] +name = "pyo3-macros-backend" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70a3b2274450ba5288bc9b8c1b69ff569d1d61189d4bff38f8d22e03d17f932b" +dependencies = [ + "heck", + "proc-macro2", + "pyo3-build-config", + "quote", + "syn", +] + [[package]] name = "quinn" version = "0.11.9" @@ -2001,6 +2081,12 @@ dependencies = [ "thiserror", ] +[[package]] +name = "reed-solomon" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13de68c877a77f35885442ac72c8beb7c2f0b09380c43b734b9d63d1db69ee54" + [[package]] name = "regex" version = "1.12.1" @@ -2480,6 +2566,12 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +[[package]] +name = "target-lexicon" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df7f62577c25e07834649fc3b39fafdc597c0a3527dc1c60129201ccfcbaa50c" + [[package]] name = "tempfile" version = "3.23.0" @@ -2794,6 +2886,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" +[[package]] +name = "unindent" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3" + [[package]] name = "unit-prefix" version = "0.5.1" @@ -3313,6 +3411,7 @@ dependencies = [ "clap", "env_logger", "log", + "pyo3", "serde", "serde_yaml", ] diff --git a/espflash/Cargo.toml b/espflash/Cargo.toml index ebd638db..7f05bcad 100644 --- a/espflash/Cargo.toml +++ b/espflash/Cargo.toml @@ -50,6 +50,7 @@ log = "0.4" md-5 = "0.10" miette = "7.6" object = "0.37" +reed-solomon = "0.2.1" regex = { version = "1.11", optional = true } serde = { version = "1.0", features = ["derive"] } serialport = { version = "4.7", default-features = false, optional = true } diff --git a/espflash/src/connection/mod.rs b/espflash/src/connection/mod.rs index 42b6d8d7..d30964d9 100644 --- a/espflash/src/connection/mod.rs +++ b/espflash/src/connection/mod.rs @@ -683,6 +683,19 @@ impl Connection { Ok(()) } + /// Updates a register by applying the new value to the masked out portion + /// of the old value. + // TODO: Is this the API we want? For many cases it's convenient to let this + // function handle it, but the resulting API feels kind of + // non-obvious. + pub(crate) fn update_reg(&mut self, addr: u32, mask: u32, new_value: u32) -> Result<(), Error> { + let masked_new_value = new_value.checked_shl(mask.trailing_zeros()).unwrap_or(0) & mask; + + let masked_old_value = self.read_reg(addr)? & !mask; + + self.write_reg(addr, masked_old_value | masked_new_value, None) + } + /// Reads a register command with a timeout. pub(crate) fn read(&mut self, len: usize) -> Result>, Error> { let mut tmp = Vec::with_capacity(1024); diff --git a/espflash/src/error.rs b/espflash/src/error.rs index c671fc7c..2f811bc4 100644 --- a/espflash/src/error.rs +++ b/espflash/src/error.rs @@ -363,6 +363,26 @@ pub enum Error { /// The efuse field is larger than 32 bit. #[error("Requested efuse field is larger than 32 bit. Use `read_efuse_le`.")] EfuseFieldTooLarge, + + /// Specified eFuse block does not exist + #[error("specified eFuse block does not exist: {0}")] + InvalidEfuseBlock(u32), + + /// Unsupported crystall frequency + #[error("Unsupported crystal frequency: {0}")] + UnsupportedXtalFrequency(String), + + /// Failed to write eFuse + #[error("Failed to write eFuse: {0}")] + WritingEfuseFailed(String), + + /// Timed out while waiting for eFuse controller to return to idle + #[error("Timed out while waiting for eFuse controller to return to idle")] + TimedOutWaitingForEfuseController, + + /// Tried to use an unsupported eFuse coding scheme + #[error("Tried to use an unsupported eFuse coding scheme: {0}")] + UnsupportedEfuseCodingScheme(String), } #[cfg(feature = "serialport")] diff --git a/espflash/src/target/efuse/esp32.rs b/espflash/src/target/efuse/esp32.rs index 81d4c1e3..3866091f 100644 --- a/espflash/src/target/efuse/esp32.rs +++ b/espflash/src/target/efuse/esp32.rs @@ -2,15 +2,72 @@ //! //! This file was automatically generated, please do not edit it manually! //! -//! Generated: 2025-11-19 12:31 +//! Generated: 2025-12-05 18:05 //! Version: 369d2d860d34e777c0f7d545a7dfc3c4 #![allow(unused)] -use super::EfuseField; +use super::{EfuseBlock, EfuseField}; -/// Total size in bytes of each block -pub(crate) const BLOCK_SIZES: &[u32] = &[28, 32, 32, 32]; +/// All eFuse blocks available on this device. +pub(crate) const BLOCKS: &[EfuseBlock] = &[ + EfuseBlock { + index: 0u8, + length: 7u8, + read_address: 0x3ff5a000u32, + write_address: 0x3ff5a01cu32, + }, + EfuseBlock { + index: 1u8, + length: 8u8, + read_address: 0x3ff5a038u32, + write_address: 0x3ff5a098u32, + }, + EfuseBlock { + index: 2u8, + length: 8u8, + read_address: 0x3ff5a058u32, + write_address: 0x3ff5a0b8u32, + }, + EfuseBlock { + index: 3u8, + length: 8u8, + read_address: 0x3ff5a078u32, + write_address: 0x3ff5a0d8u32, + }, +]; + +/// Defined eFuse registers and commands +pub(crate) mod defines { + use super::super::EfuseBlockErrors; + pub(crate) const BLOCK_ERRORS: &[EfuseBlockErrors] = &[]; + pub(crate) const EFUSE_CMD_READ: u32 = 0x1; + pub(crate) const EFUSE_BLK0_RDATA3_REG: u32 = 0x3ff5a00c; + pub(crate) const EFUSE_MEM_SIZE: u32 = 0x120; + pub(crate) const CODING_SCHEME_NONE_RECOVERY: u32 = 0x3; + pub(crate) const EFUSE_CMD_WRITE: u32 = 0x2; + pub(crate) const EFUSE_CLK_SEL0_MASK: u32 = 0xff; + pub(crate) const EFUSE_REG_DEC_STATUS_MASK: u32 = 0xfff; + pub(crate) const CODING_SCHEME_34: u32 = 0x1; + pub(crate) const EFUSE_CLK_REG: u32 = 0x3ff5a0f8; + pub(crate) const EFUSE_CODING_SCHEME_WORD: u32 = 0x6; + pub(crate) const EFUSE_DAC_CLK_DIV_MASK: u32 = 0xff; + pub(crate) const EFUSE_CODING_SCHEME_MASK: u32 = 0x3; + pub(crate) const EFUSE_CLK_SEL1_MASK: u32 = 0xff00; + pub(crate) const CODING_SCHEME_RS: u32 = 0x4; + pub(crate) const EFUSE_RD_CHIP_VER_REV2: u32 = 0x100000; + pub(crate) const EFUSE_REG_CONF: u32 = 0x3ff5a0fc; + pub(crate) const EFUSE_RD_CHIP_VER_REV1: u32 = 0x8000; + pub(crate) const EFUSE_CONF_WRITE: u32 = 0x5a5a; + pub(crate) const EFUSE_CMD_OP_MASK: u32 = 0x3; + pub(crate) const CODING_SCHEME_NONE: u32 = 0x0; + pub(crate) const CODING_SCHEME_REPEAT: u32 = 0x2; + pub(crate) const EFUSE_BLK0_RDATA5_REG: u32 = 0x3ff5a014; + pub(crate) const EFUSE_CONF_READ: u32 = 0x5aa5; + pub(crate) const EFUSE_REG_DEC_STATUS: u32 = 0x3ff5a11c; + pub(crate) const EFUSE_DAC_CONF_REG: u32 = 0x3ff5a118; + pub(crate) const EFUSE_REG_CMD: u32 = 0x3ff5a104; +} /// Efuse write disable mask pub const WR_DIS: EfuseField = EfuseField::new(0, 0, 0, 16); diff --git a/espflash/src/target/efuse/esp32c2.rs b/espflash/src/target/efuse/esp32c2.rs index d4dad029..2d74b9a6 100644 --- a/espflash/src/target/efuse/esp32c2.rs +++ b/espflash/src/target/efuse/esp32c2.rs @@ -2,15 +2,108 @@ //! //! This file was automatically generated, please do not edit it manually! //! -//! Generated: 2025-11-19 12:31 +//! Generated: 2025-12-05 18:05 //! Version: 897499b0349a608b895d467abbcf006b #![allow(unused)] -use super::EfuseField; +use super::{EfuseBlock, EfuseField}; -/// Total size in bytes of each block -pub(crate) const BLOCK_SIZES: &[u32] = &[8, 12, 32, 32]; +/// All eFuse blocks available on this device. +pub(crate) const BLOCKS: &[EfuseBlock] = &[ + EfuseBlock { + index: 0u8, + length: 2u8, + read_address: 0x6000882cu32, + write_address: 0x60008800u32, + }, + EfuseBlock { + index: 1u8, + length: 3u8, + read_address: 0x60008834u32, + write_address: 0x60008800u32, + }, + EfuseBlock { + index: 2u8, + length: 8u8, + read_address: 0x60008840u32, + write_address: 0x60008800u32, + }, + EfuseBlock { + index: 3u8, + length: 8u8, + read_address: 0x60008860u32, + write_address: 0x60008800u32, + }, +]; + +/// Defined eFuse registers and commands +pub(crate) mod defines { + use super::super::EfuseBlockErrors; + pub(crate) const BLOCK_ERRORS: &[EfuseBlockErrors] = &[ + EfuseBlockErrors { + err_num_reg: 0x60008880u32, + err_num_mask: None, + err_num_offset: None, + fail_bit_reg: 0x60008880u32, + fail_bit_offset: None, + }, + EfuseBlockErrors { + err_num_reg: 0x60008884u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x0u32), + fail_bit_reg: 0x60008884u32, + fail_bit_offset: Some(0x3u32), + }, + EfuseBlockErrors { + err_num_reg: 0x60008884u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x4u32), + fail_bit_reg: 0x60008884u32, + fail_bit_offset: Some(0x7u32), + }, + EfuseBlockErrors { + err_num_reg: 0x60008884u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x8u32), + fail_bit_reg: 0x60008884u32, + fail_bit_offset: Some(0xbu32), + }, + ]; + pub(crate) const EFUSE_DAC_NUM_M: u32 = 0x1fe00; + pub(crate) const EFUSE_PGM_CMD: u32 = 0x2; + pub(crate) const EFUSE_PWR_ON_NUM_M: u32 = 0xffff00; + pub(crate) const EFUSE_DAC_NUM_S: u32 = 0x9; + pub(crate) const EFUSE_RD_RS_ERR_REG: u32 = 0x60008884; + pub(crate) const EFUSE_PGM_DATA0_REG: u32 = 0x60008800; + pub(crate) const EFUSE_READ_CMD: u32 = 0x1; + pub(crate) const EFUSE_PWR_OFF_NUM_M: u32 = 0xffff; + pub(crate) const EFUSE_WR_TIM_CONF0_REG: u32 = 0x60008910; + pub(crate) const EFUSE_WR_TIM_CONF1_REG: u32 = 0x60008914; + pub(crate) const EFUSE_MEM_SIZE: u32 = 0x200; + pub(crate) const CODING_SCHEME_34: u32 = 0x1; + pub(crate) const CODING_SCHEME_NONE: u32 = 0x0; + pub(crate) const EFUSE_PWR_OFF_NUM_S: u32 = 0x0; + pub(crate) const CODING_SCHEME_REPEAT: u32 = 0x2; + pub(crate) const EFUSE_TPGM_INACTIVE_S: u32 = 0x8; + pub(crate) const EFUSE_CLK_REG: u32 = 0x60008888; + pub(crate) const CODING_SCHEME_NONE_RECOVERY: u32 = 0x3; + pub(crate) const EFUSE_PWR_ON_NUM_S: u32 = 0x8; + pub(crate) const EFUSE_PGM_CMD_MASK: u32 = 0x3; + pub(crate) const EFUSE_WRITE_OP_CODE: u32 = 0x5a5a; + pub(crate) const EFUSE_STATUS_REG: u32 = 0x60008890; + pub(crate) const EFUSE_CMD_REG: u32 = 0x60008894; + pub(crate) const EFUSE_CONF_REG: u32 = 0x6000888c; + pub(crate) const EFUSE_TPGM_INACTIVE_M: u32 = 0xff00; + pub(crate) const EFUSE_DAC_CONF_REG: u32 = 0x60008908; + pub(crate) const EFUSE_RD_REPEAT_ERR_REG: u32 = 0x60008880; + pub(crate) const CODING_SCHEME_RS: u32 = 0x4; + pub(crate) const EFUSE_DAC_CLK_DIV_S: u32 = 0x0; + pub(crate) const EFUSE_PGM_CHECK_VALUE0_REG: u32 = 0x60008820; + pub(crate) const EFUSE_WR_TIM_CONF2_REG: u32 = 0x60008918; + pub(crate) const EFUSE_DAC_CLK_DIV_M: u32 = 0xff; + pub(crate) const EFUSE_READ_OP_CODE: u32 = 0x5aa5; +} /// Disable programming of individual eFuses pub const WR_DIS: EfuseField = EfuseField::new(0, 0, 0, 8); diff --git a/espflash/src/target/efuse/esp32c3.rs b/espflash/src/target/efuse/esp32c3.rs index cfae4715..4c7aed05 100644 --- a/espflash/src/target/efuse/esp32c3.rs +++ b/espflash/src/target/efuse/esp32c3.rs @@ -2,15 +2,203 @@ //! //! This file was automatically generated, please do not edit it manually! //! -//! Generated: 2025-11-19 12:31 +//! Generated: 2025-12-05 18:05 //! Version: 4622cf9245401eca0eb1df8122449a6d #![allow(unused)] -use super::EfuseField; +use super::{EfuseBlock, EfuseField}; -/// Total size in bytes of each block -pub(crate) const BLOCK_SIZES: &[u32] = &[24, 24, 32, 32, 32, 32, 32, 32, 32, 32, 32]; +/// All eFuse blocks available on this device. +pub(crate) const BLOCKS: &[EfuseBlock] = &[ + EfuseBlock { + index: 0u8, + length: 6u8, + read_address: 0x6000882cu32, + write_address: 0x60008800u32, + }, + EfuseBlock { + index: 1u8, + length: 6u8, + read_address: 0x60008844u32, + write_address: 0x60008800u32, + }, + EfuseBlock { + index: 2u8, + length: 8u8, + read_address: 0x6000885cu32, + write_address: 0x60008800u32, + }, + EfuseBlock { + index: 3u8, + length: 8u8, + read_address: 0x6000887cu32, + write_address: 0x60008800u32, + }, + EfuseBlock { + index: 4u8, + length: 8u8, + read_address: 0x6000889cu32, + write_address: 0x60008800u32, + }, + EfuseBlock { + index: 5u8, + length: 8u8, + read_address: 0x600088bcu32, + write_address: 0x60008800u32, + }, + EfuseBlock { + index: 6u8, + length: 8u8, + read_address: 0x600088dcu32, + write_address: 0x60008800u32, + }, + EfuseBlock { + index: 7u8, + length: 8u8, + read_address: 0x600088fcu32, + write_address: 0x60008800u32, + }, + EfuseBlock { + index: 8u8, + length: 8u8, + read_address: 0x6000891cu32, + write_address: 0x60008800u32, + }, + EfuseBlock { + index: 9u8, + length: 8u8, + read_address: 0x6000893cu32, + write_address: 0x60008800u32, + }, + EfuseBlock { + index: 10u8, + length: 8u8, + read_address: 0x6000895cu32, + write_address: 0x60008800u32, + }, +]; + +/// Defined eFuse registers and commands +pub(crate) mod defines { + use super::super::EfuseBlockErrors; + pub(crate) const BLOCK_ERRORS: &[EfuseBlockErrors] = &[ + EfuseBlockErrors { + err_num_reg: 0x6000897cu32, + err_num_mask: None, + err_num_offset: None, + fail_bit_reg: 0x6000897cu32, + fail_bit_offset: None, + }, + EfuseBlockErrors { + err_num_reg: 0x600089c0u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x0u32), + fail_bit_reg: 0x600089c0u32, + fail_bit_offset: Some(0x7u32), + }, + EfuseBlockErrors { + err_num_reg: 0x600089c0u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x4u32), + fail_bit_reg: 0x600089c0u32, + fail_bit_offset: Some(0xbu32), + }, + EfuseBlockErrors { + err_num_reg: 0x600089c0u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x8u32), + fail_bit_reg: 0x600089c0u32, + fail_bit_offset: Some(0xfu32), + }, + EfuseBlockErrors { + err_num_reg: 0x600089c0u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0xcu32), + fail_bit_reg: 0x600089c0u32, + fail_bit_offset: Some(0x13u32), + }, + EfuseBlockErrors { + err_num_reg: 0x600089c0u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x10u32), + fail_bit_reg: 0x600089c0u32, + fail_bit_offset: Some(0x17u32), + }, + EfuseBlockErrors { + err_num_reg: 0x600089c0u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x14u32), + fail_bit_reg: 0x600089c0u32, + fail_bit_offset: Some(0x1bu32), + }, + EfuseBlockErrors { + err_num_reg: 0x600089c0u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x18u32), + fail_bit_reg: 0x600089c0u32, + fail_bit_offset: Some(0x1fu32), + }, + EfuseBlockErrors { + err_num_reg: 0x600089c0u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x1cu32), + fail_bit_reg: 0x600089c4u32, + fail_bit_offset: Some(0x3u32), + }, + EfuseBlockErrors { + err_num_reg: 0x600089c4u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x0u32), + fail_bit_reg: 0x600089c4u32, + fail_bit_offset: Some(0x7u32), + }, + EfuseBlockErrors { + err_num_reg: 0x600089c4u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x4u32), + fail_bit_reg: 0x600089c4u32, + fail_bit_offset: None, + }, + ]; + pub(crate) const CODING_SCHEME_NONE_RECOVERY: u32 = 0x3; + pub(crate) const EFUSE_RD_REPEAT_ERR1_REG: u32 = 0x60008980; + pub(crate) const EFUSE_DAC_NUM_M: u32 = 0x1fe00; + pub(crate) const EFUSE_DAC_CLK_DIV_S: u32 = 0x0; + pub(crate) const EFUSE_RD_RS_ERR0_REG: u32 = 0x600089c0; + pub(crate) const CODING_SCHEME_NONE: u32 = 0x0; + pub(crate) const EFUSE_CLK_REG: u32 = 0x600089c8; + pub(crate) const EFUSE_READ_OP_CODE: u32 = 0x5aa5; + pub(crate) const EFUSE_STATUS_REG: u32 = 0x600089d0; + pub(crate) const EFUSE_PWR_OFF_NUM_S: u32 = 0x0; + pub(crate) const EFUSE_WRITE_OP_CODE: u32 = 0x5a5a; + pub(crate) const EFUSE_DAC_CONF_REG: u32 = 0x600089e8; + pub(crate) const EFUSE_RD_REPEAT_ERR4_REG: u32 = 0x6000898c; + pub(crate) const EFUSE_RD_TIM_CONF_REG: u32 = 0x600089ec; + pub(crate) const EFUSE_PWR_OFF_NUM_M: u32 = 0xffff; + pub(crate) const EFUSE_CONF_REG: u32 = 0x600089cc; + pub(crate) const EFUSE_RD_REPEAT_ERR2_REG: u32 = 0x60008984; + pub(crate) const EFUSE_MEM_SIZE: u32 = 0x200; + pub(crate) const EFUSE_PGM_DATA0_REG: u32 = 0x60008800; + pub(crate) const EFUSE_PWR_ON_NUM_M: u32 = 0xffff00; + pub(crate) const CODING_SCHEME_34: u32 = 0x1; + pub(crate) const CODING_SCHEME_REPEAT: u32 = 0x2; + pub(crate) const EFUSE_READ_CMD: u32 = 0x1; + pub(crate) const EFUSE_WR_TIM_CONF1_REG: u32 = 0x600089f0; + pub(crate) const EFUSE_WR_TIM_CONF2_REG: u32 = 0x600089f4; + pub(crate) const CODING_SCHEME_RS: u32 = 0x4; + pub(crate) const EFUSE_PWR_ON_NUM_S: u32 = 0x8; + pub(crate) const EFUSE_RD_REPEAT_ERR0_REG: u32 = 0x6000897c; + pub(crate) const EFUSE_DAC_NUM_S: u32 = 0x9; + pub(crate) const EFUSE_RD_REPEAT_ERR3_REG: u32 = 0x60008988; + pub(crate) const EFUSE_DAC_CLK_DIV_M: u32 = 0xff; + pub(crate) const EFUSE_RD_RS_ERR1_REG: u32 = 0x600089c4; + pub(crate) const EFUSE_CHECK_VALUE0_REG: u32 = 0x60008820; + pub(crate) const EFUSE_PGM_CMD: u32 = 0x2; + pub(crate) const EFUSE_DATE_REG: u32 = 0x600089fc; + pub(crate) const EFUSE_PGM_CMD_MASK: u32 = 0x3; + pub(crate) const EFUSE_CMD_REG: u32 = 0x600089d4; +} /// Disable programming of individual eFuses pub const WR_DIS: EfuseField = EfuseField::new(0, 0, 0, 32); diff --git a/espflash/src/target/efuse/esp32c5.rs b/espflash/src/target/efuse/esp32c5.rs index af055171..2fcd2e12 100644 --- a/espflash/src/target/efuse/esp32c5.rs +++ b/espflash/src/target/efuse/esp32c5.rs @@ -2,15 +2,203 @@ //! //! This file was automatically generated, please do not edit it manually! //! -//! Generated: 2025-11-19 12:31 +//! Generated: 2025-12-05 18:05 //! Version: 31c7fe3f5f4e0a55b178a57126c0aca7 #![allow(unused)] -use super::EfuseField; +use super::{EfuseBlock, EfuseField}; -/// Total size in bytes of each block -pub(crate) const BLOCK_SIZES: &[u32] = &[24, 24, 32, 32, 32, 32, 32, 32, 32, 32, 32]; +/// All eFuse blocks available on this device. +pub(crate) const BLOCKS: &[EfuseBlock] = &[ + EfuseBlock { + index: 0u8, + length: 6u8, + read_address: 0x600b482cu32, + write_address: 0x600b4800u32, + }, + EfuseBlock { + index: 1u8, + length: 6u8, + read_address: 0x600b4844u32, + write_address: 0x600b4800u32, + }, + EfuseBlock { + index: 2u8, + length: 8u8, + read_address: 0x600b485cu32, + write_address: 0x600b4800u32, + }, + EfuseBlock { + index: 3u8, + length: 8u8, + read_address: 0x600b487cu32, + write_address: 0x600b4800u32, + }, + EfuseBlock { + index: 4u8, + length: 8u8, + read_address: 0x600b489cu32, + write_address: 0x600b4800u32, + }, + EfuseBlock { + index: 5u8, + length: 8u8, + read_address: 0x600b48bcu32, + write_address: 0x600b4800u32, + }, + EfuseBlock { + index: 6u8, + length: 8u8, + read_address: 0x600b48dcu32, + write_address: 0x600b4800u32, + }, + EfuseBlock { + index: 7u8, + length: 8u8, + read_address: 0x600b48fcu32, + write_address: 0x600b4800u32, + }, + EfuseBlock { + index: 8u8, + length: 8u8, + read_address: 0x600b491cu32, + write_address: 0x600b4800u32, + }, + EfuseBlock { + index: 9u8, + length: 8u8, + read_address: 0x600b493cu32, + write_address: 0x600b4800u32, + }, + EfuseBlock { + index: 10u8, + length: 8u8, + read_address: 0x600b495cu32, + write_address: 0x600b4800u32, + }, +]; + +/// Defined eFuse registers and commands +pub(crate) mod defines { + use super::super::EfuseBlockErrors; + pub(crate) const BLOCK_ERRORS: &[EfuseBlockErrors] = &[ + EfuseBlockErrors { + err_num_reg: 0x600b497cu32, + err_num_mask: None, + err_num_offset: None, + fail_bit_reg: 0x600b497cu32, + fail_bit_offset: None, + }, + EfuseBlockErrors { + err_num_reg: 0x600b4990u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x0u32), + fail_bit_reg: 0x600b4990u32, + fail_bit_offset: Some(0x3u32), + }, + EfuseBlockErrors { + err_num_reg: 0x600b4990u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x4u32), + fail_bit_reg: 0x600b4990u32, + fail_bit_offset: Some(0x7u32), + }, + EfuseBlockErrors { + err_num_reg: 0x600b4990u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x8u32), + fail_bit_reg: 0x600b4990u32, + fail_bit_offset: Some(0xbu32), + }, + EfuseBlockErrors { + err_num_reg: 0x600b4990u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0xcu32), + fail_bit_reg: 0x600b4990u32, + fail_bit_offset: Some(0xfu32), + }, + EfuseBlockErrors { + err_num_reg: 0x600b4990u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x10u32), + fail_bit_reg: 0x600b4990u32, + fail_bit_offset: Some(0x13u32), + }, + EfuseBlockErrors { + err_num_reg: 0x600b4990u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x14u32), + fail_bit_reg: 0x600b4990u32, + fail_bit_offset: Some(0x17u32), + }, + EfuseBlockErrors { + err_num_reg: 0x600b4990u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x18u32), + fail_bit_reg: 0x600b4990u32, + fail_bit_offset: Some(0x1bu32), + }, + EfuseBlockErrors { + err_num_reg: 0x600b4990u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x1cu32), + fail_bit_reg: 0x600b4990u32, + fail_bit_offset: Some(0x1fu32), + }, + EfuseBlockErrors { + err_num_reg: 0x600b4994u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x0u32), + fail_bit_reg: 0x600b4994u32, + fail_bit_offset: Some(0x3u32), + }, + EfuseBlockErrors { + err_num_reg: 0x600b4994u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x4u32), + fail_bit_reg: 0x600b4994u32, + fail_bit_offset: Some(0x7u32), + }, + ]; + pub(crate) const EFUSE_WR_TIM_CONF2_REG: u32 = 0x600b49f8; + pub(crate) const EFUSE_DAC_CONF_REG: u32 = 0x600b49ec; + pub(crate) const EFUSE_RD_REPEAT_ERR2_REG: u32 = 0x600b4984; + pub(crate) const CODING_SCHEME_REPEAT: u32 = 0x2; + pub(crate) const EFUSE_DAC_NUM_S: u32 = 0x9; + pub(crate) const CODING_SCHEME_34: u32 = 0x1; + pub(crate) const EFUSE_CLK_REG: u32 = 0x600b49c8; + pub(crate) const EFUSE_READ_CMD: u32 = 0x1; + pub(crate) const EFUSE_PGM_CMD_MASK: u32 = 0x3; + pub(crate) const EFUSE_RD_REPEAT_ERR0_REG: u32 = 0x600b497c; + pub(crate) const EFUSE_PGM_CMD: u32 = 0x2; + pub(crate) const EFUSE_PWR_ON_NUM_M: u32 = 0xffff00; + pub(crate) const EFUSE_PWR_OFF_NUM_M: u32 = 0xffff; + pub(crate) const EFUSE_PGM_DATA0_REG: u32 = 0x600b4800; + pub(crate) const EFUSE_RD_REPEAT_ERR1_REG: u32 = 0x600b4980; + pub(crate) const EFUSE_RD_RS_ERR0_REG: u32 = 0x600b4990; + pub(crate) const CODING_SCHEME_NONE_RECOVERY: u32 = 0x3; + pub(crate) const EFUSE_DAC_CLK_DIV_M: u32 = 0xff; + pub(crate) const CODING_SCHEME_RS: u32 = 0x4; + pub(crate) const EFUSE_WRITE_OP_CODE: u32 = 0x5a5a; + pub(crate) const EFUSE_RD_RS_ERR1_REG: u32 = 0x600b4994; + pub(crate) const EFUSE_DAC_CLK_DIV_S: u32 = 0x0; + pub(crate) const EFUSE_CMD_REG: u32 = 0x600b49d8; + pub(crate) const EFUSE_RD_REPEAT_ERR4_REG: u32 = 0x600b498c; + pub(crate) const EFUSE_RD_REPEAT_ERR3_REG: u32 = 0x600b4988; + pub(crate) const EFUSE_WR_TIM_CONF1_REG: u32 = 0x600b49f4; + pub(crate) const EFUSE_PWR_ON_NUM_S: u32 = 0x8; + pub(crate) const EFUSE_STATUS_REG: u32 = 0x600b49d4; + pub(crate) const EFUSE_RD_TIM_CONF_REG: u32 = 0x600b49f0; + pub(crate) const EFUSE_CHECK_VALUE0_REG: u32 = 0x600b4820; + pub(crate) const CODING_SCHEME_NONE: u32 = 0x0; + pub(crate) const EFUSE_DATE_REG: u32 = 0x600b4998; + pub(crate) const EFUSE_DAC_NUM_M: u32 = 0x1fe00; + pub(crate) const EFUSE_MEM_SIZE: u32 = 0x200; + pub(crate) const EFUSE_READ_OP_CODE: u32 = 0x5aa5; + pub(crate) const EFUSE_PWR_OFF_NUM_S: u32 = 0x0; + pub(crate) const EFUSE_CONF_REG: u32 = 0x600b49cc; +} /// Disable programming of individual eFuses pub const WR_DIS: EfuseField = EfuseField::new(0, 0, 0, 32); diff --git a/espflash/src/target/efuse/esp32c6.rs b/espflash/src/target/efuse/esp32c6.rs index eed1b593..74864ee4 100644 --- a/espflash/src/target/efuse/esp32c6.rs +++ b/espflash/src/target/efuse/esp32c6.rs @@ -2,15 +2,203 @@ //! //! This file was automatically generated, please do not edit it manually! //! -//! Generated: 2025-11-19 12:31 +//! Generated: 2025-12-05 18:05 //! Version: df46b69f0ed3913114ba53d3a0b2b843 #![allow(unused)] -use super::EfuseField; +use super::{EfuseBlock, EfuseField}; -/// Total size in bytes of each block -pub(crate) const BLOCK_SIZES: &[u32] = &[24, 24, 32, 32, 32, 32, 32, 32, 32, 32, 32]; +/// All eFuse blocks available on this device. +pub(crate) const BLOCKS: &[EfuseBlock] = &[ + EfuseBlock { + index: 0u8, + length: 6u8, + read_address: 0x600b082cu32, + write_address: 0x600b0800u32, + }, + EfuseBlock { + index: 1u8, + length: 6u8, + read_address: 0x600b0844u32, + write_address: 0x600b0800u32, + }, + EfuseBlock { + index: 2u8, + length: 8u8, + read_address: 0x600b085cu32, + write_address: 0x600b0800u32, + }, + EfuseBlock { + index: 3u8, + length: 8u8, + read_address: 0x600b087cu32, + write_address: 0x600b0800u32, + }, + EfuseBlock { + index: 4u8, + length: 8u8, + read_address: 0x600b089cu32, + write_address: 0x600b0800u32, + }, + EfuseBlock { + index: 5u8, + length: 8u8, + read_address: 0x600b08bcu32, + write_address: 0x600b0800u32, + }, + EfuseBlock { + index: 6u8, + length: 8u8, + read_address: 0x600b08dcu32, + write_address: 0x600b0800u32, + }, + EfuseBlock { + index: 7u8, + length: 8u8, + read_address: 0x600b08fcu32, + write_address: 0x600b0800u32, + }, + EfuseBlock { + index: 8u8, + length: 8u8, + read_address: 0x600b091cu32, + write_address: 0x600b0800u32, + }, + EfuseBlock { + index: 9u8, + length: 8u8, + read_address: 0x600b093cu32, + write_address: 0x600b0800u32, + }, + EfuseBlock { + index: 10u8, + length: 8u8, + read_address: 0x600b095cu32, + write_address: 0x600b0800u32, + }, +]; + +/// Defined eFuse registers and commands +pub(crate) mod defines { + use super::super::EfuseBlockErrors; + pub(crate) const BLOCK_ERRORS: &[EfuseBlockErrors] = &[ + EfuseBlockErrors { + err_num_reg: 0x600b097cu32, + err_num_mask: None, + err_num_offset: None, + fail_bit_reg: 0x600b097cu32, + fail_bit_offset: None, + }, + EfuseBlockErrors { + err_num_reg: 0x600b09c0u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x0u32), + fail_bit_reg: 0x600b09c0u32, + fail_bit_offset: Some(0x3u32), + }, + EfuseBlockErrors { + err_num_reg: 0x600b09c0u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x4u32), + fail_bit_reg: 0x600b09c0u32, + fail_bit_offset: Some(0x7u32), + }, + EfuseBlockErrors { + err_num_reg: 0x600b09c0u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x8u32), + fail_bit_reg: 0x600b09c0u32, + fail_bit_offset: Some(0xbu32), + }, + EfuseBlockErrors { + err_num_reg: 0x600b09c0u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0xcu32), + fail_bit_reg: 0x600b09c0u32, + fail_bit_offset: Some(0xfu32), + }, + EfuseBlockErrors { + err_num_reg: 0x600b09c0u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x10u32), + fail_bit_reg: 0x600b09c0u32, + fail_bit_offset: Some(0x13u32), + }, + EfuseBlockErrors { + err_num_reg: 0x600b09c0u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x14u32), + fail_bit_reg: 0x600b09c0u32, + fail_bit_offset: Some(0x17u32), + }, + EfuseBlockErrors { + err_num_reg: 0x600b09c0u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x18u32), + fail_bit_reg: 0x600b09c0u32, + fail_bit_offset: Some(0x1bu32), + }, + EfuseBlockErrors { + err_num_reg: 0x600b09c0u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x1cu32), + fail_bit_reg: 0x600b09c0u32, + fail_bit_offset: Some(0x1fu32), + }, + EfuseBlockErrors { + err_num_reg: 0x600b09c4u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x0u32), + fail_bit_reg: 0x600b09c4u32, + fail_bit_offset: Some(0x3u32), + }, + EfuseBlockErrors { + err_num_reg: 0x600b09c4u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x4u32), + fail_bit_reg: 0x600b09c4u32, + fail_bit_offset: Some(0x7u32), + }, + ]; + pub(crate) const EFUSE_PWR_ON_NUM_M: u32 = 0xffff00; + pub(crate) const EFUSE_RD_TIM_CONF_REG: u32 = 0x600b09ec; + pub(crate) const EFUSE_RD_REPEAT_ERR4_REG: u32 = 0x600b098c; + pub(crate) const EFUSE_PGM_DATA0_REG: u32 = 0x600b0800; + pub(crate) const EFUSE_CMD_REG: u32 = 0x600b09d4; + pub(crate) const EFUSE_RD_RS_ERR0_REG: u32 = 0x600b09c0; + pub(crate) const CODING_SCHEME_REPEAT: u32 = 0x2; + pub(crate) const EFUSE_RD_REPEAT_ERR3_REG: u32 = 0x600b0988; + pub(crate) const EFUSE_DAC_NUM_M: u32 = 0x1fe00; + pub(crate) const EFUSE_RD_REPEAT_ERR2_REG: u32 = 0x600b0984; + pub(crate) const EFUSE_DATE_REG: u32 = 0x600b09fc; + pub(crate) const EFUSE_DAC_CONF_REG: u32 = 0x600b09e8; + pub(crate) const EFUSE_PGM_CMD_MASK: u32 = 0x3; + pub(crate) const CODING_SCHEME_NONE_RECOVERY: u32 = 0x3; + pub(crate) const EFUSE_DAC_CLK_DIV_M: u32 = 0xff; + pub(crate) const EFUSE_MEM_SIZE: u32 = 0x200; + pub(crate) const EFUSE_READ_CMD: u32 = 0x1; + pub(crate) const EFUSE_DAC_NUM_S: u32 = 0x9; + pub(crate) const EFUSE_RD_RS_ERR1_REG: u32 = 0x600b09c4; + pub(crate) const EFUSE_READ_OP_CODE: u32 = 0x5aa5; + pub(crate) const EFUSE_PWR_OFF_NUM_M: u32 = 0xffff; + pub(crate) const EFUSE_PWR_ON_NUM_S: u32 = 0x8; + pub(crate) const EFUSE_RD_REPEAT_ERR0_REG: u32 = 0x600b097c; + pub(crate) const CODING_SCHEME_34: u32 = 0x1; + pub(crate) const CODING_SCHEME_RS: u32 = 0x4; + pub(crate) const EFUSE_CHECK_VALUE0_REG: u32 = 0x600b0820; + pub(crate) const EFUSE_CONF_REG: u32 = 0x600b09cc; + pub(crate) const EFUSE_PWR_OFF_NUM_S: u32 = 0x0; + pub(crate) const EFUSE_DAC_CLK_DIV_S: u32 = 0x0; + pub(crate) const EFUSE_WR_TIM_CONF1_REG: u32 = 0x600b09f0; + pub(crate) const CODING_SCHEME_NONE: u32 = 0x0; + pub(crate) const EFUSE_PGM_CMD: u32 = 0x2; + pub(crate) const EFUSE_WR_TIM_CONF2_REG: u32 = 0x600b09f4; + pub(crate) const EFUSE_WRITE_OP_CODE: u32 = 0x5a5a; + pub(crate) const EFUSE_STATUS_REG: u32 = 0x600b09d0; + pub(crate) const EFUSE_RD_REPEAT_ERR1_REG: u32 = 0x600b0980; + pub(crate) const EFUSE_CLK_REG: u32 = 0x600b09c8; +} /// Disable programming of individual eFuses pub const WR_DIS: EfuseField = EfuseField::new(0, 0, 0, 32); diff --git a/espflash/src/target/efuse/esp32h2.rs b/espflash/src/target/efuse/esp32h2.rs index 519167dc..79c68059 100644 --- a/espflash/src/target/efuse/esp32h2.rs +++ b/espflash/src/target/efuse/esp32h2.rs @@ -2,15 +2,203 @@ //! //! This file was automatically generated, please do not edit it manually! //! -//! Generated: 2025-11-19 12:31 +//! Generated: 2025-12-05 18:05 //! Version: 44563d2af4ebdba4db6c0a34a50c94f9 #![allow(unused)] -use super::EfuseField; +use super::{EfuseBlock, EfuseField}; -/// Total size in bytes of each block -pub(crate) const BLOCK_SIZES: &[u32] = &[24, 24, 32, 32, 32, 32, 32, 32, 32, 32, 32]; +/// All eFuse blocks available on this device. +pub(crate) const BLOCKS: &[EfuseBlock] = &[ + EfuseBlock { + index: 0u8, + length: 6u8, + read_address: 0x600b082cu32, + write_address: 0x600b0800u32, + }, + EfuseBlock { + index: 1u8, + length: 6u8, + read_address: 0x600b0844u32, + write_address: 0x600b0800u32, + }, + EfuseBlock { + index: 2u8, + length: 8u8, + read_address: 0x600b085cu32, + write_address: 0x600b0800u32, + }, + EfuseBlock { + index: 3u8, + length: 8u8, + read_address: 0x600b087cu32, + write_address: 0x600b0800u32, + }, + EfuseBlock { + index: 4u8, + length: 8u8, + read_address: 0x600b089cu32, + write_address: 0x600b0800u32, + }, + EfuseBlock { + index: 5u8, + length: 8u8, + read_address: 0x600b08bcu32, + write_address: 0x600b0800u32, + }, + EfuseBlock { + index: 6u8, + length: 8u8, + read_address: 0x600b08dcu32, + write_address: 0x600b0800u32, + }, + EfuseBlock { + index: 7u8, + length: 8u8, + read_address: 0x600b08fcu32, + write_address: 0x600b0800u32, + }, + EfuseBlock { + index: 8u8, + length: 8u8, + read_address: 0x600b091cu32, + write_address: 0x600b0800u32, + }, + EfuseBlock { + index: 9u8, + length: 8u8, + read_address: 0x600b093cu32, + write_address: 0x600b0800u32, + }, + EfuseBlock { + index: 10u8, + length: 8u8, + read_address: 0x600b095cu32, + write_address: 0x600b0800u32, + }, +]; + +/// Defined eFuse registers and commands +pub(crate) mod defines { + use super::super::EfuseBlockErrors; + pub(crate) const BLOCK_ERRORS: &[EfuseBlockErrors] = &[ + EfuseBlockErrors { + err_num_reg: 0x600b097cu32, + err_num_mask: None, + err_num_offset: None, + fail_bit_reg: 0x600b097cu32, + fail_bit_offset: None, + }, + EfuseBlockErrors { + err_num_reg: 0x600b09c0u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x0u32), + fail_bit_reg: 0x600b09c0u32, + fail_bit_offset: Some(0x3u32), + }, + EfuseBlockErrors { + err_num_reg: 0x600b09c0u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x4u32), + fail_bit_reg: 0x600b09c0u32, + fail_bit_offset: Some(0x7u32), + }, + EfuseBlockErrors { + err_num_reg: 0x600b09c0u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x8u32), + fail_bit_reg: 0x600b09c0u32, + fail_bit_offset: Some(0xbu32), + }, + EfuseBlockErrors { + err_num_reg: 0x600b09c0u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0xcu32), + fail_bit_reg: 0x600b09c0u32, + fail_bit_offset: Some(0xfu32), + }, + EfuseBlockErrors { + err_num_reg: 0x600b09c0u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x10u32), + fail_bit_reg: 0x600b09c0u32, + fail_bit_offset: Some(0x13u32), + }, + EfuseBlockErrors { + err_num_reg: 0x600b09c0u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x14u32), + fail_bit_reg: 0x600b09c0u32, + fail_bit_offset: Some(0x17u32), + }, + EfuseBlockErrors { + err_num_reg: 0x600b09c0u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x18u32), + fail_bit_reg: 0x600b09c0u32, + fail_bit_offset: Some(0x1bu32), + }, + EfuseBlockErrors { + err_num_reg: 0x600b09c0u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x1cu32), + fail_bit_reg: 0x600b09c0u32, + fail_bit_offset: Some(0x1fu32), + }, + EfuseBlockErrors { + err_num_reg: 0x600b09c4u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x0u32), + fail_bit_reg: 0x600b09c4u32, + fail_bit_offset: Some(0x3u32), + }, + EfuseBlockErrors { + err_num_reg: 0x600b09c4u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x4u32), + fail_bit_reg: 0x600b09c4u32, + fail_bit_offset: Some(0x7u32), + }, + ]; + pub(crate) const EFUSE_READ_CMD: u32 = 0x1; + pub(crate) const EFUSE_CHECK_VALUE0_REG: u32 = 0x600b0820; + pub(crate) const EFUSE_WR_TIM_CONF2_REG: u32 = 0x600b09f4; + pub(crate) const EFUSE_RD_REPEAT_ERR1_REG: u32 = 0x600b0980; + pub(crate) const EFUSE_MEM_SIZE: u32 = 0x200; + pub(crate) const EFUSE_STATUS_REG: u32 = 0x600b09d0; + pub(crate) const CODING_SCHEME_34: u32 = 0x1; + pub(crate) const EFUSE_RD_RS_ERR1_REG: u32 = 0x600b09c4; + pub(crate) const EFUSE_CLK_REG: u32 = 0x600b09c8; + pub(crate) const EFUSE_DAC_NUM_M: u32 = 0x1fe00; + pub(crate) const EFUSE_RD_RS_ERR0_REG: u32 = 0x600b09c0; + pub(crate) const EFUSE_RD_REPEAT_ERR2_REG: u32 = 0x600b0984; + pub(crate) const EFUSE_DAC_CLK_DIV_M: u32 = 0xff; + pub(crate) const EFUSE_WRITE_OP_CODE: u32 = 0x5a5a; + pub(crate) const EFUSE_PWR_OFF_NUM_M: u32 = 0xffff; + pub(crate) const EFUSE_DATE_REG: u32 = 0x600b09fc; + pub(crate) const EFUSE_PGM_DATA0_REG: u32 = 0x600b0800; + pub(crate) const EFUSE_CONF_REG: u32 = 0x600b09cc; + pub(crate) const EFUSE_RD_REPEAT_ERR3_REG: u32 = 0x600b0988; + pub(crate) const CODING_SCHEME_NONE_RECOVERY: u32 = 0x3; + pub(crate) const EFUSE_DAC_CONF_REG: u32 = 0x600b09e8; + pub(crate) const EFUSE_PGM_CMD_MASK: u32 = 0x3; + pub(crate) const EFUSE_RD_REPEAT_ERR4_REG: u32 = 0x600b098c; + pub(crate) const EFUSE_PGM_CMD: u32 = 0x2; + pub(crate) const EFUSE_PWR_ON_NUM_S: u32 = 0x8; + pub(crate) const EFUSE_READ_OP_CODE: u32 = 0x5aa5; + pub(crate) const EFUSE_CMD_REG: u32 = 0x600b09d4; + pub(crate) const CODING_SCHEME_RS: u32 = 0x4; + pub(crate) const EFUSE_RD_TIM_CONF_REG: u32 = 0x600b09ec; + pub(crate) const EFUSE_DAC_NUM_S: u32 = 0x9; + pub(crate) const CODING_SCHEME_NONE: u32 = 0x0; + pub(crate) const EFUSE_RD_REPEAT_ERR0_REG: u32 = 0x600b097c; + pub(crate) const EFUSE_DAC_CLK_DIV_S: u32 = 0x0; + pub(crate) const CODING_SCHEME_REPEAT: u32 = 0x2; + pub(crate) const EFUSE_PWR_OFF_NUM_S: u32 = 0x0; + pub(crate) const EFUSE_PWR_ON_NUM_M: u32 = 0xffff00; + pub(crate) const EFUSE_WR_TIM_CONF1_REG: u32 = 0x600b09f0; +} /// Disable programming of individual eFuses pub const WR_DIS: EfuseField = EfuseField::new(0, 0, 0, 32); diff --git a/espflash/src/target/efuse/esp32p4.rs b/espflash/src/target/efuse/esp32p4.rs index 73fea9b4..567a81e5 100644 --- a/espflash/src/target/efuse/esp32p4.rs +++ b/espflash/src/target/efuse/esp32p4.rs @@ -2,15 +2,203 @@ //! //! This file was automatically generated, please do not edit it manually! //! -//! Generated: 2025-11-19 12:31 +//! Generated: 2025-12-05 18:05 //! Version: f7765f0ac3faf4b54f8c1f064307522c #![allow(unused)] -use super::EfuseField; +use super::{EfuseBlock, EfuseField}; -/// Total size in bytes of each block -pub(crate) const BLOCK_SIZES: &[u32] = &[24, 24, 32, 32, 32, 32, 32, 32, 32, 32, 32]; +/// All eFuse blocks available on this device. +pub(crate) const BLOCKS: &[EfuseBlock] = &[ + EfuseBlock { + index: 0u8, + length: 6u8, + read_address: 0x5012d02cu32, + write_address: 0x5012d000u32, + }, + EfuseBlock { + index: 1u8, + length: 6u8, + read_address: 0x5012d044u32, + write_address: 0x5012d000u32, + }, + EfuseBlock { + index: 2u8, + length: 8u8, + read_address: 0x5012d05cu32, + write_address: 0x5012d000u32, + }, + EfuseBlock { + index: 3u8, + length: 8u8, + read_address: 0x5012d07cu32, + write_address: 0x5012d000u32, + }, + EfuseBlock { + index: 4u8, + length: 8u8, + read_address: 0x5012d09cu32, + write_address: 0x5012d000u32, + }, + EfuseBlock { + index: 5u8, + length: 8u8, + read_address: 0x5012d0bcu32, + write_address: 0x5012d000u32, + }, + EfuseBlock { + index: 6u8, + length: 8u8, + read_address: 0x5012d0dcu32, + write_address: 0x5012d000u32, + }, + EfuseBlock { + index: 7u8, + length: 8u8, + read_address: 0x5012d0fcu32, + write_address: 0x5012d000u32, + }, + EfuseBlock { + index: 8u8, + length: 8u8, + read_address: 0x5012d11cu32, + write_address: 0x5012d000u32, + }, + EfuseBlock { + index: 9u8, + length: 8u8, + read_address: 0x5012d13cu32, + write_address: 0x5012d000u32, + }, + EfuseBlock { + index: 10u8, + length: 8u8, + read_address: 0x5012d15cu32, + write_address: 0x5012d000u32, + }, +]; + +/// Defined eFuse registers and commands +pub(crate) mod defines { + use super::super::EfuseBlockErrors; + pub(crate) const BLOCK_ERRORS: &[EfuseBlockErrors] = &[ + EfuseBlockErrors { + err_num_reg: 0x5012d17cu32, + err_num_mask: None, + err_num_offset: None, + fail_bit_reg: 0x5012d17cu32, + fail_bit_offset: None, + }, + EfuseBlockErrors { + err_num_reg: 0x5012d1c0u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x0u32), + fail_bit_reg: 0x5012d1c0u32, + fail_bit_offset: Some(0x3u32), + }, + EfuseBlockErrors { + err_num_reg: 0x5012d1c0u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x4u32), + fail_bit_reg: 0x5012d1c0u32, + fail_bit_offset: Some(0x7u32), + }, + EfuseBlockErrors { + err_num_reg: 0x5012d1c0u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x8u32), + fail_bit_reg: 0x5012d1c0u32, + fail_bit_offset: Some(0xbu32), + }, + EfuseBlockErrors { + err_num_reg: 0x5012d1c0u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0xcu32), + fail_bit_reg: 0x5012d1c0u32, + fail_bit_offset: Some(0xfu32), + }, + EfuseBlockErrors { + err_num_reg: 0x5012d1c0u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x10u32), + fail_bit_reg: 0x5012d1c0u32, + fail_bit_offset: Some(0x13u32), + }, + EfuseBlockErrors { + err_num_reg: 0x5012d1c0u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x14u32), + fail_bit_reg: 0x5012d1c0u32, + fail_bit_offset: Some(0x17u32), + }, + EfuseBlockErrors { + err_num_reg: 0x5012d1c0u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x18u32), + fail_bit_reg: 0x5012d1c0u32, + fail_bit_offset: Some(0x1bu32), + }, + EfuseBlockErrors { + err_num_reg: 0x5012d1c0u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x1cu32), + fail_bit_reg: 0x5012d1c0u32, + fail_bit_offset: Some(0x1fu32), + }, + EfuseBlockErrors { + err_num_reg: 0x5012d1c4u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x0u32), + fail_bit_reg: 0x5012d1c4u32, + fail_bit_offset: Some(0x3u32), + }, + EfuseBlockErrors { + err_num_reg: 0x5012d1c4u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x4u32), + fail_bit_reg: 0x5012d1c4u32, + fail_bit_offset: Some(0x7u32), + }, + ]; + pub(crate) const CODING_SCHEME_NONE_RECOVERY: u32 = 0x3; + pub(crate) const EFUSE_PWR_OFF_NUM_S: u32 = 0x0; + pub(crate) const EFUSE_DAC_CLK_DIV_S: u32 = 0x0; + pub(crate) const EFUSE_DAC_NUM_S: u32 = 0x9; + pub(crate) const EFUSE_DATE_REG: u32 = 0x5012d1fc; + pub(crate) const EFUSE_WR_TIM_CONF1_REG: u32 = 0x5012d1f0; + pub(crate) const EFUSE_CONF_REG: u32 = 0x5012d1cc; + pub(crate) const EFUSE_RD_TIM_CONF_REG: u32 = 0x5012d1ec; + pub(crate) const EFUSE_READ_OP_CODE: u32 = 0x5aa5; + pub(crate) const EFUSE_RD_REPEAT_ERR3_REG: u32 = 0x5012d188; + pub(crate) const EFUSE_RD_RS_ERR0_REG: u32 = 0x5012d1c0; + pub(crate) const EFUSE_WR_TIM_CONF2_REG: u32 = 0x5012d1f4; + pub(crate) const EFUSE_PWR_ON_NUM_S: u32 = 0x8; + pub(crate) const EFUSE_CMD_REG: u32 = 0x5012d1d4; + pub(crate) const EFUSE_STATUS_REG: u32 = 0x5012d1d0; + pub(crate) const EFUSE_PGM_CMD: u32 = 0x2; + pub(crate) const CODING_SCHEME_REPEAT: u32 = 0x2; + pub(crate) const EFUSE_DAC_CONF_REG: u32 = 0x5012d1e8; + pub(crate) const EFUSE_READ_CMD: u32 = 0x1; + pub(crate) const EFUSE_RD_REPEAT_ERR0_REG: u32 = 0x5012d17c; + pub(crate) const EFUSE_PGM_CMD_MASK: u32 = 0x3; + pub(crate) const CODING_SCHEME_NONE: u32 = 0x0; + pub(crate) const EFUSE_WRITE_OP_CODE: u32 = 0x5a5a; + pub(crate) const EFUSE_PWR_OFF_NUM_M: u32 = 0xffff; + pub(crate) const EFUSE_CLK_REG: u32 = 0x5012d1c8; + pub(crate) const CODING_SCHEME_RS: u32 = 0x4; + pub(crate) const EFUSE_DAC_NUM_M: u32 = 0x1fe00; + pub(crate) const EFUSE_CHECK_VALUE0_REG: u32 = 0x5012d020; + pub(crate) const EFUSE_PWR_ON_NUM_M: u32 = 0xffff00; + pub(crate) const EFUSE_MEM_SIZE: u32 = 0x200; + pub(crate) const EFUSE_DAC_CLK_DIV_M: u32 = 0xff; + pub(crate) const EFUSE_RD_REPEAT_ERR1_REG: u32 = 0x5012d180; + pub(crate) const CODING_SCHEME_34: u32 = 0x1; + pub(crate) const EFUSE_RD_RS_ERR1_REG: u32 = 0x5012d1c4; + pub(crate) const EFUSE_RD_REPEAT_ERR2_REG: u32 = 0x5012d184; + pub(crate) const EFUSE_RD_REPEAT_ERR4_REG: u32 = 0x5012d18c; + pub(crate) const EFUSE_PGM_DATA0_REG: u32 = 0x5012d000; +} /// Disable programming of individual eFuses pub const WR_DIS: EfuseField = EfuseField::new(0, 0, 0, 32); diff --git a/espflash/src/target/efuse/esp32s2.rs b/espflash/src/target/efuse/esp32s2.rs index ab61752b..a38dbcef 100644 --- a/espflash/src/target/efuse/esp32s2.rs +++ b/espflash/src/target/efuse/esp32s2.rs @@ -2,15 +2,216 @@ //! //! This file was automatically generated, please do not edit it manually! //! -//! Generated: 2025-11-19 12:31 +//! Generated: 2025-12-05 18:05 //! Version: 888a61f6f500d9c7ee0aa32016b0bee7 #![allow(unused)] -use super::EfuseField; +use super::{EfuseBlock, EfuseField}; -/// Total size in bytes of each block -pub(crate) const BLOCK_SIZES: &[u32] = &[24, 24, 32, 32, 32, 32, 32, 32, 32, 32, 32]; +/// All eFuse blocks available on this device. +pub(crate) const BLOCKS: &[EfuseBlock] = &[ + EfuseBlock { + index: 0u8, + length: 6u8, + read_address: 0x3f41a02cu32, + write_address: 0x3f41a000u32, + }, + EfuseBlock { + index: 1u8, + length: 6u8, + read_address: 0x3f41a044u32, + write_address: 0x3f41a000u32, + }, + EfuseBlock { + index: 2u8, + length: 8u8, + read_address: 0x3f41a05cu32, + write_address: 0x3f41a000u32, + }, + EfuseBlock { + index: 3u8, + length: 8u8, + read_address: 0x3f41a07cu32, + write_address: 0x3f41a000u32, + }, + EfuseBlock { + index: 4u8, + length: 8u8, + read_address: 0x3f41a09cu32, + write_address: 0x3f41a000u32, + }, + EfuseBlock { + index: 5u8, + length: 8u8, + read_address: 0x3f41a0bcu32, + write_address: 0x3f41a000u32, + }, + EfuseBlock { + index: 6u8, + length: 8u8, + read_address: 0x3f41a0dcu32, + write_address: 0x3f41a000u32, + }, + EfuseBlock { + index: 7u8, + length: 8u8, + read_address: 0x3f41a0fcu32, + write_address: 0x3f41a000u32, + }, + EfuseBlock { + index: 8u8, + length: 8u8, + read_address: 0x3f41a11cu32, + write_address: 0x3f41a000u32, + }, + EfuseBlock { + index: 9u8, + length: 8u8, + read_address: 0x3f41a13cu32, + write_address: 0x3f41a000u32, + }, + EfuseBlock { + index: 10u8, + length: 8u8, + read_address: 0x3f41a15cu32, + write_address: 0x3f41a000u32, + }, +]; + +/// Defined eFuse registers and commands +pub(crate) mod defines { + use super::super::EfuseBlockErrors; + pub(crate) const BLOCK_ERRORS: &[EfuseBlockErrors] = &[ + EfuseBlockErrors { + err_num_reg: 0x3f41a17cu32, + err_num_mask: None, + err_num_offset: None, + fail_bit_reg: 0x3f41a17cu32, + fail_bit_offset: None, + }, + EfuseBlockErrors { + err_num_reg: 0x3f41a194u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x0u32), + fail_bit_reg: 0x3f41a194u32, + fail_bit_offset: Some(0x3u32), + }, + EfuseBlockErrors { + err_num_reg: 0x3f41a194u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x4u32), + fail_bit_reg: 0x3f41a194u32, + fail_bit_offset: Some(0x7u32), + }, + EfuseBlockErrors { + err_num_reg: 0x3f41a194u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x8u32), + fail_bit_reg: 0x3f41a194u32, + fail_bit_offset: Some(0xbu32), + }, + EfuseBlockErrors { + err_num_reg: 0x3f41a194u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0xcu32), + fail_bit_reg: 0x3f41a194u32, + fail_bit_offset: Some(0xfu32), + }, + EfuseBlockErrors { + err_num_reg: 0x3f41a194u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x10u32), + fail_bit_reg: 0x3f41a194u32, + fail_bit_offset: Some(0x13u32), + }, + EfuseBlockErrors { + err_num_reg: 0x3f41a194u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x14u32), + fail_bit_reg: 0x3f41a194u32, + fail_bit_offset: Some(0x17u32), + }, + EfuseBlockErrors { + err_num_reg: 0x3f41a194u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x18u32), + fail_bit_reg: 0x3f41a194u32, + fail_bit_offset: Some(0x1bu32), + }, + EfuseBlockErrors { + err_num_reg: 0x3f41a194u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x1cu32), + fail_bit_reg: 0x3f41a194u32, + fail_bit_offset: Some(0x1fu32), + }, + EfuseBlockErrors { + err_num_reg: 0x3f41a198u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x0u32), + fail_bit_reg: 0x3f41a198u32, + fail_bit_offset: Some(0x3u32), + }, + EfuseBlockErrors { + err_num_reg: 0x3f41a198u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x4u32), + fail_bit_reg: 0x3f41a198u32, + fail_bit_offset: Some(0x7u32), + }, + ]; + pub(crate) const EFUSE_RD_TIM_CONF_REG: u32 = 0x3f41a1ec; + pub(crate) const EFUSE_DAC_CLK_DIV_S: u32 = 0x0; + pub(crate) const CODING_SCHEME_34: u32 = 0x1; + pub(crate) const EFUSE_PGM_DATA0_REG: u32 = 0x3f41a000; + pub(crate) const EFUSE_TRD_M: u32 = 0xff00; + pub(crate) const EFUSE_WR_TIM_CONF0_REG: u32 = 0x3f41a1f0; + pub(crate) const EFUSE_RD_REPEAT_ERR0_REG: u32 = 0x3f41a17c; + pub(crate) const EFUSE_TRD_S: u32 = 0x8; + pub(crate) const EFUSE_WR_TIM_CONF2_REG: u32 = 0x3f41a1f8; + pub(crate) const EFUSE_PGM_CMD_MASK: u32 = 0x3; + pub(crate) const EFUSE_RD_REPEAT_ERR1_REG: u32 = 0x3f41a180; + pub(crate) const EFUSE_RD_REPEAT_ERR4_REG: u32 = 0x3f41a18c; + pub(crate) const CODING_SCHEME_RS: u32 = 0x4; + pub(crate) const EFUSE_CLK_REG: u32 = 0x3f41a1c8; + pub(crate) const EFUSE_RD_RS_ERR1_REG: u32 = 0x3f41a198; + pub(crate) const CODING_SCHEME_NONE_RECOVERY: u32 = 0x3; + pub(crate) const CODING_SCHEME_REPEAT: u32 = 0x2; + pub(crate) const EFUSE_CMD_REG: u32 = 0x3f41a1d4; + pub(crate) const EFUSE_PGM_CMD: u32 = 0x2; + pub(crate) const EFUSE_RD_REPEAT_ERR2_REG: u32 = 0x3f41a184; + pub(crate) const EFUSE_TSUR_A_S: u32 = 0x10; + pub(crate) const EFUSE_RD_REPEAT_ERR3_REG: u32 = 0x3f41a188; + pub(crate) const EFUSE_TSUP_A_M: u32 = 0xff; + pub(crate) const EFUSE_DAC_CLK_DIV_M: u32 = 0xff; + pub(crate) const EFUSE_PWR_OFF_NUM_S: u32 = 0x0; + pub(crate) const EFUSE_THP_A_S: u32 = 0x0; + pub(crate) const EFUSE_PWR_ON_NUM_M: u32 = 0xffff00; + pub(crate) const EFUSE_MEM_SIZE: u32 = 0x200; + pub(crate) const EFUSE_READ_OP_CODE: u32 = 0x5aa5; + pub(crate) const EFUSE_TSUP_A_S: u32 = 0x0; + pub(crate) const EFUSE_PWR_OFF_NUM_M: u32 = 0xffff; + pub(crate) const EFUSE_CONF_REG: u32 = 0x3f41a1cc; + pub(crate) const EFUSE_THR_A_S: u32 = 0x0; + pub(crate) const EFUSE_WRITE_OP_CODE: u32 = 0x5a5a; + pub(crate) const EFUSE_TPGM_INACTIVE_S: u32 = 0x8; + pub(crate) const EFUSE_CHECK_VALUE0_REG: u32 = 0x3f41a020; + pub(crate) const EFUSE_RD_RS_ERR0_REG: u32 = 0x3f41a194; + pub(crate) const EFUSE_WR_TIM_CONF1_REG: u32 = 0x3f41a1f4; + pub(crate) const EFUSE_TPGM_INACTIVE_M: u32 = 0xff00; + pub(crate) const EFUSE_STATUS_REG: u32 = 0x3f41a1d0; + pub(crate) const EFUSE_TPGM_S: u32 = 0x10; + pub(crate) const EFUSE_THR_A_M: u32 = 0xff; + pub(crate) const EFUSE_READ_CMD: u32 = 0x1; + pub(crate) const EFUSE_PWR_ON_NUM_S: u32 = 0x8; + pub(crate) const EFUSE_TPGM_M: u32 = 0xffff0000; + pub(crate) const EFUSE_TSUR_A_M: u32 = 0xff0000; + pub(crate) const EFUSE_DATE_REG: u32 = 0x3f41a1fc; + pub(crate) const CODING_SCHEME_NONE: u32 = 0x0; + pub(crate) const EFUSE_DAC_CONF_REG: u32 = 0x3f41a1e8; + pub(crate) const EFUSE_THP_A_M: u32 = 0xff; +} /// Disable programming of individual eFuses pub const WR_DIS: EfuseField = EfuseField::new(0, 0, 0, 32); diff --git a/espflash/src/target/efuse/esp32s3.rs b/espflash/src/target/efuse/esp32s3.rs index 54e41bea..1b48b3e3 100644 --- a/espflash/src/target/efuse/esp32s3.rs +++ b/espflash/src/target/efuse/esp32s3.rs @@ -2,15 +2,204 @@ //! //! This file was automatically generated, please do not edit it manually! //! -//! Generated: 2025-11-19 12:31 +//! Generated: 2025-12-05 18:05 //! Version: 7127dd097e72bb90d0b790d460993126 #![allow(unused)] -use super::EfuseField; +use super::{EfuseBlock, EfuseField}; -/// Total size in bytes of each block -pub(crate) const BLOCK_SIZES: &[u32] = &[24, 24, 32, 32, 32, 32, 32, 32, 32, 32, 32]; +/// All eFuse blocks available on this device. +pub(crate) const BLOCKS: &[EfuseBlock] = &[ + EfuseBlock { + index: 0u8, + length: 6u8, + read_address: 0x6000702cu32, + write_address: 0x60007000u32, + }, + EfuseBlock { + index: 1u8, + length: 6u8, + read_address: 0x60007044u32, + write_address: 0x60007000u32, + }, + EfuseBlock { + index: 2u8, + length: 8u8, + read_address: 0x6000705cu32, + write_address: 0x60007000u32, + }, + EfuseBlock { + index: 3u8, + length: 8u8, + read_address: 0x6000707cu32, + write_address: 0x60007000u32, + }, + EfuseBlock { + index: 4u8, + length: 8u8, + read_address: 0x6000709cu32, + write_address: 0x60007000u32, + }, + EfuseBlock { + index: 5u8, + length: 8u8, + read_address: 0x600070bcu32, + write_address: 0x60007000u32, + }, + EfuseBlock { + index: 6u8, + length: 8u8, + read_address: 0x600070dcu32, + write_address: 0x60007000u32, + }, + EfuseBlock { + index: 7u8, + length: 8u8, + read_address: 0x600070fcu32, + write_address: 0x60007000u32, + }, + EfuseBlock { + index: 8u8, + length: 8u8, + read_address: 0x6000711cu32, + write_address: 0x60007000u32, + }, + EfuseBlock { + index: 9u8, + length: 8u8, + read_address: 0x6000713cu32, + write_address: 0x60007000u32, + }, + EfuseBlock { + index: 10u8, + length: 8u8, + read_address: 0x6000715cu32, + write_address: 0x60007000u32, + }, +]; + +/// Defined eFuse registers and commands +pub(crate) mod defines { + use super::super::EfuseBlockErrors; + pub(crate) const BLOCK_ERRORS: &[EfuseBlockErrors] = &[ + EfuseBlockErrors { + err_num_reg: 0x6000717cu32, + err_num_mask: None, + err_num_offset: None, + fail_bit_reg: 0x6000717cu32, + fail_bit_offset: None, + }, + EfuseBlockErrors { + err_num_reg: 0x600071c0u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x0u32), + fail_bit_reg: 0x600071c0u32, + fail_bit_offset: Some(0x3u32), + }, + EfuseBlockErrors { + err_num_reg: 0x600071c0u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x4u32), + fail_bit_reg: 0x600071c0u32, + fail_bit_offset: Some(0x7u32), + }, + EfuseBlockErrors { + err_num_reg: 0x600071c0u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x8u32), + fail_bit_reg: 0x600071c0u32, + fail_bit_offset: Some(0xbu32), + }, + EfuseBlockErrors { + err_num_reg: 0x600071c0u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0xcu32), + fail_bit_reg: 0x600071c0u32, + fail_bit_offset: Some(0xfu32), + }, + EfuseBlockErrors { + err_num_reg: 0x600071c0u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x10u32), + fail_bit_reg: 0x600071c0u32, + fail_bit_offset: Some(0x13u32), + }, + EfuseBlockErrors { + err_num_reg: 0x600071c0u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x14u32), + fail_bit_reg: 0x600071c0u32, + fail_bit_offset: Some(0x17u32), + }, + EfuseBlockErrors { + err_num_reg: 0x600071c0u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x18u32), + fail_bit_reg: 0x600071c0u32, + fail_bit_offset: Some(0x1bu32), + }, + EfuseBlockErrors { + err_num_reg: 0x600071c0u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x1cu32), + fail_bit_reg: 0x600071c0u32, + fail_bit_offset: Some(0x1fu32), + }, + EfuseBlockErrors { + err_num_reg: 0x600071c4u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x0u32), + fail_bit_reg: 0x600071c4u32, + fail_bit_offset: Some(0x3u32), + }, + EfuseBlockErrors { + err_num_reg: 0x600071c4u32, + err_num_mask: Some(0x7u32), + err_num_offset: Some(0x4u32), + fail_bit_reg: 0x600071c4u32, + fail_bit_offset: Some(0x7u32), + }, + ]; + pub(crate) const CODING_SCHEME_RS: u32 = 0x4; + pub(crate) const CODING_SCHEME_REPEAT: u32 = 0x2; + pub(crate) const EFUSE_RD_REPEAT_ERR0_REG: u32 = 0x6000717c; + pub(crate) const EFUSE_CLK_REG: u32 = 0x600071c8; + pub(crate) const EFUSE_RD_REPEAT_ERR4_REG: u32 = 0x6000718c; + pub(crate) const EFUSE_RD_RS_ERR0_REG: u32 = 0x600071c0; + pub(crate) const EFUSE_PGM_CMD: u32 = 0x2; + pub(crate) const EFUSE_RD_TIM_CONF_REG: u32 = 0x600071ec; + pub(crate) const EFUSE_RD_REPEAT_ERR1_REG: u32 = 0x60007180; + pub(crate) const EFUSE_CONF_REG: u32 = 0x600071cc; + pub(crate) const EFUSE_PWR_ON_NUM_S: u32 = 0x8; + pub(crate) const EFUSE_PWR_OFF_NUM_S: u32 = 0x0; + pub(crate) const EFUSE_CHECK_VALUE0_REG: u32 = 0x60007020; + pub(crate) const EFUSE_RD_REPEAT_ERR2_REG: u32 = 0x60007184; + pub(crate) const EFUSE_ADDR_MASK: u32 = 0xfff; + pub(crate) const EFUSE_STATUS_REG: u32 = 0x600071d0; + pub(crate) const EFUSE_READ_OP_CODE: u32 = 0x5aa5; + pub(crate) const EFUSE_PWR_ON_NUM_M: u32 = 0xffff00; + pub(crate) const EFUSE_WRITE_OP_CODE: u32 = 0x5a5a; + pub(crate) const EFUSE_WR_TIM_CONF1_REG: u32 = 0x600071f4; + pub(crate) const CODING_SCHEME_NONE: u32 = 0x0; + pub(crate) const EFUSE_RD_RS_ERR1_REG: u32 = 0x600071c4; + pub(crate) const CODING_SCHEME_34: u32 = 0x1; + pub(crate) const EFUSE_DAC_NUM_S: u32 = 0x9; + pub(crate) const EFUSE_PGM_CMD_MASK: u32 = 0x3; + pub(crate) const EFUSE_DAC_CLK_DIV_S: u32 = 0x0; + pub(crate) const EFUSE_DATE_REG: u32 = 0x600071fc; + pub(crate) const EFUSE_DAC_CLK_DIV_M: u32 = 0xff; + pub(crate) const EFUSE_DAC_NUM_M: u32 = 0x1fe00; + pub(crate) const EFUSE_CMD_REG: u32 = 0x600071d4; + pub(crate) const EFUSE_PGM_DATA0_REG: u32 = 0x60007000; + pub(crate) const EFUSE_DAC_CONF_REG: u32 = 0x600071e8; + pub(crate) const CODING_SCHEME_NONE_RECOVERY: u32 = 0x3; + pub(crate) const EFUSE_RD_REPEAT_ERR3_REG: u32 = 0x60007188; + pub(crate) const EFUSE_WR_TIM_CONF2_REG: u32 = 0x600071f8; + pub(crate) const EFUSE_MEM_SIZE: u32 = 0x200; + pub(crate) const EFUSE_READ_CMD: u32 = 0x1; + pub(crate) const EFUSE_PWR_OFF_NUM_M: u32 = 0xffff; +} /// Disable programming of individual eFuses pub const WR_DIS: EfuseField = EfuseField::new(0, 0, 0, 32); diff --git a/espflash/src/target/efuse/mod.rs b/espflash/src/target/efuse/mod.rs index d71cae7f..bb7081ed 100644 --- a/espflash/src/target/efuse/mod.rs +++ b/espflash/src/target/efuse/mod.rs @@ -15,6 +15,30 @@ pub mod esp32p4; pub mod esp32s2; pub mod esp32s3; +#[allow(unused)] +#[derive(Clone, Copy)] +pub(crate) struct EfuseBlock { + pub(crate) index: u8, + /// Number of registers that this block contains. + /// + /// Each register is a single 4-byte word. + pub(crate) length: u8, + /// Read address for this eFuse block. + pub(crate) read_address: u32, + /// Write address for this eFus block. + pub(crate) write_address: u32, +} + +#[allow(unused)] +#[derive(Clone, Copy)] +pub(crate) struct EfuseBlockErrors { + pub(crate) err_num_reg: u32, + pub(crate) err_num_mask: Option, + pub(crate) err_num_offset: Option, + pub(crate) fail_bit_reg: u32, + pub(crate) fail_bit_offset: Option, +} + /// An eFuse field which can be read from a target device. #[allow(unused)] #[derive(Debug, Clone, serde::Deserialize)] diff --git a/espflash/src/target/mod.rs b/espflash/src/target/mod.rs index c789bd21..19a3f73a 100644 --- a/espflash/src/target/mod.rs +++ b/espflash/src/target/mod.rs @@ -20,9 +20,14 @@ pub use self::flash_target::{ use crate::{ Error, flasher::{FLASH_WRITE_SIZE, FlashFrequency}, + target::efuse::EfuseBlock, }; #[cfg(feature = "serialport")] -use crate::{connection::Connection, flasher::SpiAttachParams, target::efuse::EfuseField}; +use crate::{ + connection::Connection, + flasher::SpiAttachParams, + target::efuse::{EfuseBlockErrors, EfuseField}, +}; pub mod efuse; @@ -397,20 +402,53 @@ impl Chip { } } + /// Returns the eFuse block definition of the specified block. + fn block(&self, block: u32) -> Result { + let blocks = match self { + Chip::Esp32 => efuse::esp32::BLOCKS, + Chip::Esp32c2 => efuse::esp32c2::BLOCKS, + Chip::Esp32c3 => efuse::esp32c3::BLOCKS, + Chip::Esp32c5 => efuse::esp32c5::BLOCKS, + Chip::Esp32c6 => efuse::esp32c6::BLOCKS, + Chip::Esp32h2 => efuse::esp32h2::BLOCKS, + Chip::Esp32p4 => efuse::esp32p4::BLOCKS, + Chip::Esp32s2 => efuse::esp32s2::BLOCKS, + Chip::Esp32s3 => efuse::esp32s3::BLOCKS, + }; + + if block as usize >= blocks.len() { + return Err(Error::InvalidEfuseBlock(block)); + } + + Ok(blocks[block as usize]) + } + + #[cfg(feature = "serialport")] + fn block_errors(self, block: EfuseBlock) -> Result, Error> { + let block_errors = match self { + Chip::Esp32 => return Ok(None), + Chip::Esp32c2 => efuse::esp32c2::defines::BLOCK_ERRORS, + Chip::Esp32c3 => efuse::esp32c3::defines::BLOCK_ERRORS, + Chip::Esp32c5 => efuse::esp32c5::defines::BLOCK_ERRORS, + Chip::Esp32c6 => efuse::esp32c6::defines::BLOCK_ERRORS, + Chip::Esp32h2 => efuse::esp32h2::defines::BLOCK_ERRORS, + Chip::Esp32p4 => efuse::esp32p4::defines::BLOCK_ERRORS, + Chip::Esp32s2 => efuse::esp32s2::defines::BLOCK_ERRORS, + Chip::Esp32s3 => efuse::esp32s3::defines::BLOCK_ERRORS, + }; + + if block.index as usize >= block_errors.len() { + return Err(Error::InvalidEfuseBlock(block.index.into())); + } + + Ok(Some(block_errors[block.index as usize])) + } + /// Returns the size of the specified block for the implementing target. /// device pub fn block_size(&self, block: usize) -> u32 { - match self { - Chip::Esp32 => efuse::esp32::BLOCK_SIZES[block], - Chip::Esp32c2 => efuse::esp32c2::BLOCK_SIZES[block], - Chip::Esp32c3 => efuse::esp32c3::BLOCK_SIZES[block], - Chip::Esp32c5 => efuse::esp32c5::BLOCK_SIZES[block], - Chip::Esp32c6 => efuse::esp32c6::BLOCK_SIZES[block], - Chip::Esp32h2 => efuse::esp32h2::BLOCK_SIZES[block], - Chip::Esp32p4 => efuse::esp32p4::BLOCK_SIZES[block], - Chip::Esp32s2 => efuse::esp32s2::BLOCK_SIZES[block], - Chip::Esp32s3 => efuse::esp32s3::BLOCK_SIZES[block], - } + let block = self.block(block as u32).unwrap(); + block.length as u32 * 4 } /// Given an active connection, read the specified field of the eFuse @@ -458,7 +496,10 @@ impl Chip { let bit_end = std::cmp::min(bit_count, (bytes.len() * 8) as u32) + bit_off; let mut last_word_off = bit_off / 32; - let mut last_word = read_raw(connection, self.block_address(block) + last_word_off * 4)?; + let mut last_word = read_raw( + connection, + self.block(block)?.read_address + last_word_off * 4, + )?; let word_bit_off = bit_off % 32; let word_bit_ext = 32 - word_bit_off; @@ -468,7 +509,10 @@ impl Chip { if word_off != last_word_off { // Read a new word: last_word_off = word_off; - last_word = read_raw(connection, self.block_address(block) + last_word_off * 4)?; + last_word = read_raw( + connection, + self.block(block)?.read_address + last_word_off * 4, + )?; } let mut word = last_word >> word_bit_off; @@ -478,7 +522,10 @@ impl Chip { if word_bit_len > word_bit_ext { // Read the next word: last_word_off = word_off; - last_word = read_raw(connection, self.block_address(block) + last_word_off * 4)?; + last_word = read_raw( + connection, + self.block(block)?.read_address + last_word_off * 4, + )?; // Append bits from a beginning of the next word: word |= last_word.wrapping_shl(32 - word_bit_off); }; @@ -507,18 +554,6 @@ impl Chip { Ok(unsafe { output.assume_init() }) } - #[cfg(feature = "serialport")] - fn block_address(&self, block: u32) -> u32 { - let block0_addr = self.efuse_reg() + self.block0_offset(); - - let mut block_offset = 0; - for b in 0..block { - block_offset += self.block_size(b as usize); - } - - block0_addr + block_offset - } - /// Read the raw word in the specified eFuse block, without performing any /// bit-shifting or masking of the read value. #[cfg(feature = "serialport")] @@ -528,7 +563,7 @@ impl Chip { block: u32, word: u32, ) -> Result { - let addr = self.block_address(block) + (word * 0x4); + let addr = self.block(block)?.read_address + (word * 0x4); connection.read_reg(addr) } @@ -1058,6 +1093,713 @@ impl Chip { } } +#[cfg(feature = "serialport")] +impl Chip { + /// Poll the eFuse controller status until it's idle. + fn wait_efuse_idle(self, connection: &mut Connection) -> Result<(), Error> { + let (cmd_reg, cmds) = match self { + Chip::Esp32 => (efuse::esp32::defines::EFUSE_REG_CMD, u32::MAX), + Chip::Esp32c2 => ( + efuse::esp32c2::defines::EFUSE_CMD_REG, + efuse::esp32c2::defines::EFUSE_PGM_CMD | efuse::esp32c2::defines::EFUSE_READ_CMD, + ), + Chip::Esp32c3 => ( + efuse::esp32c3::defines::EFUSE_CMD_REG, + efuse::esp32c3::defines::EFUSE_PGM_CMD | efuse::esp32c3::defines::EFUSE_READ_CMD, + ), + Chip::Esp32c5 => ( + efuse::esp32c5::defines::EFUSE_CMD_REG, + efuse::esp32c5::defines::EFUSE_PGM_CMD | efuse::esp32c5::defines::EFUSE_READ_CMD, + ), + Chip::Esp32c6 => ( + efuse::esp32c6::defines::EFUSE_CMD_REG, + efuse::esp32c6::defines::EFUSE_PGM_CMD | efuse::esp32c6::defines::EFUSE_READ_CMD, + ), + Chip::Esp32h2 => ( + efuse::esp32h2::defines::EFUSE_CMD_REG, + efuse::esp32h2::defines::EFUSE_PGM_CMD | efuse::esp32h2::defines::EFUSE_READ_CMD, + ), + Chip::Esp32p4 => ( + efuse::esp32p4::defines::EFUSE_CMD_REG, + efuse::esp32p4::defines::EFUSE_PGM_CMD | efuse::esp32p4::defines::EFUSE_READ_CMD, + ), + Chip::Esp32s2 => ( + efuse::esp32s2::defines::EFUSE_CMD_REG, + efuse::esp32s2::defines::EFUSE_PGM_CMD | efuse::esp32s2::defines::EFUSE_READ_CMD, + ), + Chip::Esp32s3 => ( + efuse::esp32s3::defines::EFUSE_CMD_REG, + efuse::esp32s3::defines::EFUSE_PGM_CMD | efuse::esp32s3::defines::EFUSE_READ_CMD, + ), + }; + + // `esptool` has a 0.25 second timeout. + let deadline = std::time::Instant::now() + std::time::Duration::from_millis(250); + while std::time::Instant::now() < deadline { + // Wait until `EFUSE_CMD_REG` reads as zero twice in a row. `esptool.py` says + // that "due to a hardware error, we have to read READ_CMD again to + // make sure the efuse clock is normal" but doesn't provide any + // references. See if this is documented in the errata. + if (connection.read_reg(cmd_reg)? & cmds) != 0 { + continue; + } + if (connection.read_reg(cmd_reg)? & cmds) != 0 { + continue; + } + + return Ok(()); + } + + Err(Error::TimedOutWaitingForEfuseController) + } + + /// Configure the eFuse controller for writing. + fn configure_efuse_write_timing(&self, connection: &mut Connection) -> Result<(), Error> { + self.wait_efuse_idle(connection)?; + let xtal_freq = self.xtal_frequency(connection)?; + + match self { + Chip::Esp32 => { + let (clk_sel0, clk_sel1, dac_clk_div) = match xtal_freq { + XtalFrequency::_26Mhz => (250, 255, 52), + XtalFrequency::_40Mhz => (160, 255, 80), + other => { + return Err(Error::UnsupportedXtalFrequency(format!( + "Only 26 MHz and 40 MHz is supported (xtal was {other})" + ))); + } + }; + + connection.update_reg( + efuse::esp32::defines::EFUSE_DAC_CONF_REG, + efuse::esp32::defines::EFUSE_DAC_CLK_DIV_MASK, + dac_clk_div, + )?; + connection.update_reg( + efuse::esp32::defines::EFUSE_CLK_REG, + efuse::esp32::defines::EFUSE_CLK_SEL0_MASK, + clk_sel0, + )?; + connection.update_reg( + efuse::esp32::defines::EFUSE_CLK_REG, + efuse::esp32::defines::EFUSE_CLK_SEL1_MASK, + clk_sel1, + )?; + } + + Chip::Esp32c2 => { + if ![XtalFrequency::_26Mhz, XtalFrequency::_40Mhz].contains(&xtal_freq) { + return Err(Error::UnsupportedXtalFrequency(format!( + "Only 26 MHz and 40 MHz is supported (xtal was {xtal_freq})" + ))); + } + + connection.update_reg( + efuse::esp32c2::defines::EFUSE_DAC_CONF_REG, + efuse::esp32c2::defines::EFUSE_DAC_NUM_M, + 0xFF, + )?; + connection.update_reg( + efuse::esp32c2::defines::EFUSE_DAC_CONF_REG, + efuse::esp32c2::defines::EFUSE_DAC_CLK_DIV_M, + 0x28, + )?; + connection.update_reg( + efuse::esp32c2::defines::EFUSE_WR_TIM_CONF1_REG, + efuse::esp32c2::defines::EFUSE_PWR_ON_NUM_M, + 0x3000, + )?; + connection.update_reg( + efuse::esp32c2::defines::EFUSE_WR_TIM_CONF2_REG, + efuse::esp32c2::defines::EFUSE_PWR_OFF_NUM_M, + 0x190, + )?; + + let tpgm_inactive_val = if xtal_freq == XtalFrequency::_40Mhz { + 200 + } else { + 130 + }; + connection.update_reg( + efuse::esp32c2::defines::EFUSE_WR_TIM_CONF0_REG, + efuse::esp32c2::defines::EFUSE_TPGM_INACTIVE_M, + tpgm_inactive_val, + )?; + } + + Chip::Esp32c3 => { + if xtal_freq != XtalFrequency::_40Mhz { + return Err(Error::UnsupportedXtalFrequency(format!( + "Only 40 MHz is supported (xtal was {xtal_freq})" + ))); + } + + connection.update_reg( + efuse::esp32c3::defines::EFUSE_DAC_CONF_REG, + efuse::esp32c3::defines::EFUSE_DAC_NUM_M, + 0xFF, + )?; + connection.update_reg( + efuse::esp32c3::defines::EFUSE_DAC_CONF_REG, + efuse::esp32c3::defines::EFUSE_DAC_CLK_DIV_M, + 0x28, + )?; + connection.update_reg( + efuse::esp32c3::defines::EFUSE_WR_TIM_CONF1_REG, + efuse::esp32c3::defines::EFUSE_PWR_ON_NUM_M, + 0x3000, + )?; + connection.update_reg( + efuse::esp32c3::defines::EFUSE_WR_TIM_CONF2_REG, + efuse::esp32c3::defines::EFUSE_PWR_OFF_NUM_M, + 0x190, + )?; + } + + Chip::Esp32c5 => { + if ![XtalFrequency::_40Mhz, XtalFrequency::_48Mhz].contains(&xtal_freq) { + return Err(Error::UnsupportedXtalFrequency(format!( + "Only 40 MHz and 48 MHz is supported (xtal was {xtal_freq})" + ))); + } + + connection.update_reg( + efuse::esp32c5::defines::EFUSE_DAC_CONF_REG, + efuse::esp32c5::defines::EFUSE_DAC_NUM_M, + 0xFF, + )?; + connection.update_reg( + efuse::esp32c5::defines::EFUSE_DAC_CONF_REG, + efuse::esp32c5::defines::EFUSE_DAC_CLK_DIV_M, + 0x28, + )?; + connection.update_reg( + efuse::esp32c5::defines::EFUSE_WR_TIM_CONF1_REG, + efuse::esp32c5::defines::EFUSE_PWR_ON_NUM_M, + 0x3000, + )?; + connection.update_reg( + efuse::esp32c5::defines::EFUSE_WR_TIM_CONF2_REG, + efuse::esp32c5::defines::EFUSE_PWR_OFF_NUM_M, + 0x190, + )?; + } + + Chip::Esp32c6 => { + if xtal_freq != XtalFrequency::_40Mhz { + return Err(Error::UnsupportedXtalFrequency(format!( + "Only 40 MHz is supported (xtal was {xtal_freq})" + ))); + } + + connection.update_reg( + efuse::esp32c6::defines::EFUSE_DAC_CONF_REG, + efuse::esp32c6::defines::EFUSE_DAC_NUM_M, + 0xFF, + )?; + connection.update_reg( + efuse::esp32c6::defines::EFUSE_DAC_CONF_REG, + efuse::esp32c6::defines::EFUSE_DAC_CLK_DIV_M, + 0x28, + )?; + connection.update_reg( + efuse::esp32c6::defines::EFUSE_WR_TIM_CONF1_REG, + efuse::esp32c6::defines::EFUSE_PWR_ON_NUM_M, + 0x3000, + )?; + connection.update_reg( + efuse::esp32c6::defines::EFUSE_WR_TIM_CONF2_REG, + efuse::esp32c6::defines::EFUSE_PWR_OFF_NUM_M, + 0x190, + )?; + } + + Chip::Esp32h2 => { + if xtal_freq != XtalFrequency::_32Mhz { + return Err(Error::UnsupportedXtalFrequency(format!( + "Only 32 MHz is supported (xtal was {xtal_freq})" + ))); + } + + connection.update_reg( + efuse::esp32s3::defines::EFUSE_DAC_CONF_REG, + efuse::esp32s3::defines::EFUSE_DAC_NUM_M, + 0xFF, + )?; + connection.update_reg( + efuse::esp32s3::defines::EFUSE_DAC_CONF_REG, + efuse::esp32s3::defines::EFUSE_DAC_CLK_DIV_M, + 0x28, + )?; + connection.update_reg( + efuse::esp32s3::defines::EFUSE_WR_TIM_CONF1_REG, + efuse::esp32s3::defines::EFUSE_PWR_ON_NUM_M, + 0x3000, + )?; + connection.update_reg( + efuse::esp32s3::defines::EFUSE_WR_TIM_CONF2_REG, + efuse::esp32s3::defines::EFUSE_PWR_OFF_NUM_M, + 0x190, + )?; + } + + Chip::Esp32p4 => { + if xtal_freq != XtalFrequency::_40Mhz { + return Err(Error::UnsupportedXtalFrequency(format!( + "Only 40 MHz is supported (xtal was {xtal_freq})" + ))); + } + } + + Chip::Esp32s2 => { + // The datasheet lists parameters for 80 MHz and 20 MHz as well, but `esptool` + // doesn't support detecting either of those frequencies, so it seems like we + // only need to support 40 MHz here? + if xtal_freq != XtalFrequency::_40Mhz { + return Err(Error::UnsupportedXtalFrequency(format!( + "Only 40 MHz is supported (xtal was {xtal_freq})" + ))); + } + + // From `EFUSE_PROGRAMMING_TIMING_PARAMETERS` in + // `espefuse/efuse/esp32s2/mem_definition.py` + let (efuse_tsup_a, efuse_tpgm, efuse_thp_a, efuse_tpgm_inactive) = + (0x1, 0x190, 0x1, 0x2); + connection.update_reg( + efuse::esp32s2::defines::EFUSE_WR_TIM_CONF1_REG, + efuse::esp32s2::defines::EFUSE_TSUP_A_M, + efuse_tsup_a, + )?; + connection.update_reg( + efuse::esp32s2::defines::EFUSE_WR_TIM_CONF0_REG, + efuse::esp32s2::defines::EFUSE_TPGM_M, + efuse_tpgm, + )?; + connection.update_reg( + efuse::esp32s2::defines::EFUSE_WR_TIM_CONF0_REG, + efuse::esp32s2::defines::EFUSE_THP_A_M, + efuse_thp_a, + )?; + connection.update_reg( + efuse::esp32s2::defines::EFUSE_WR_TIM_CONF0_REG, + efuse::esp32s2::defines::EFUSE_TPGM_INACTIVE_M, + efuse_tpgm_inactive, + )?; + + // From `VDDQ_TIMING_PARAMETERS` in `espefuse/efuse/esp32s2/mem_definition.py` + let (efuse_dac_clk_div, efuse_pwr_on_num, efuse_pwr_off_num) = (0x50, 0x5100, 0x80); + connection.update_reg( + efuse::esp32s2::defines::EFUSE_DAC_CONF_REG, + efuse::esp32s2::defines::EFUSE_DAC_CLK_DIV_M, + efuse_dac_clk_div, + )?; + connection.update_reg( + efuse::esp32s2::defines::EFUSE_WR_TIM_CONF1_REG, + efuse::esp32s2::defines::EFUSE_PWR_ON_NUM_M, + efuse_pwr_on_num, + )?; + connection.update_reg( + efuse::esp32s2::defines::EFUSE_WR_TIM_CONF2_REG, + efuse::esp32s2::defines::EFUSE_PWR_OFF_NUM_M, + efuse_pwr_off_num, + )?; + + // From `EFUSE_READING_PARAMETERS` in `espefuse/efuse/esp32s2/mem_definition.py` + let (_efuse_tsur_a, efuse_trd, efuse_thr_a) = (0x1, 0x2, 0x1); + // This is commented out in `esptool` for some reason. + // TODO: Check TRM and ask `esptool` devs whether this is correct, and + // preferably why. + // + // connection.update_reg( + // efuse::esp32s2::defines::EFUSE_RD_TIM_CONF_REG, + // efuse::esp32s2::defines::EFUSE_TSUR_A_M, + // efuse_tsur_a, + // )?; + connection.update_reg( + efuse::esp32s2::defines::EFUSE_RD_TIM_CONF_REG, + efuse::esp32s2::defines::EFUSE_TRD_M, + efuse_trd, + )?; + connection.update_reg( + efuse::esp32s2::defines::EFUSE_RD_TIM_CONF_REG, + efuse::esp32s2::defines::EFUSE_THR_A_M, + efuse_thr_a, + )?; + } + + Chip::Esp32s3 => { + if xtal_freq != XtalFrequency::_40Mhz { + return Err(Error::UnsupportedXtalFrequency(format!( + "Only 40 MHz is supported (xtal was {xtal_freq})" + ))); + } + + connection.update_reg( + efuse::esp32s3::defines::EFUSE_DAC_CONF_REG, + efuse::esp32s3::defines::EFUSE_DAC_NUM_M, + 0xFF, + )?; + connection.update_reg( + efuse::esp32s3::defines::EFUSE_DAC_CONF_REG, + efuse::esp32s3::defines::EFUSE_DAC_CLK_DIV_M, + 0x28, + )?; + connection.update_reg( + efuse::esp32s3::defines::EFUSE_WR_TIM_CONF1_REG, + efuse::esp32s3::defines::EFUSE_PWR_ON_NUM_M, + 0x3000, + )?; + connection.update_reg( + efuse::esp32s3::defines::EFUSE_WR_TIM_CONF2_REG, + efuse::esp32s3::defines::EFUSE_PWR_OFF_NUM_M, + 0x190, + )?; + } + } + + Ok(()) + } + + fn efuse_coding_scheme( + self, + connection: &mut Connection, + block: EfuseBlock, + ) -> Result { + // Block 0 always has coding scheme `None`. + if block.index == 0 { + return Ok(CodingScheme::None); + } + + match self { + Chip::Esp32 => { + match self.read_efuse_le::(connection, efuse::esp32::CODING_SCHEME)? { + efuse::esp32::defines::CODING_SCHEME_NONE => Ok(CodingScheme::None), + efuse::esp32::defines::CODING_SCHEME_NONE_RECOVERY => Ok(CodingScheme::None), + efuse::esp32::defines::CODING_SCHEME_34 => Ok(CodingScheme::_34), + efuse::esp32::defines::CODING_SCHEME_REPEAT => { + Err(Error::UnsupportedEfuseCodingScheme("Repeat".to_owned())) + } + invalid => Err(Error::UnsupportedEfuseCodingScheme(format!( + "Invalid scheme: {invalid}" + ))), + } + } + Chip::Esp32c2 + | Chip::Esp32c3 + | Chip::Esp32c5 + | Chip::Esp32c6 + | Chip::Esp32h2 + | Chip::Esp32p4 + | Chip::Esp32s2 + | Chip::Esp32s3 => Ok(CodingScheme::ReedSolomon), + } + } + + /// Trigger the eFuse controller to update its internal registers. + fn trigger_efuse_register_read(&self, connection: &mut Connection) -> Result<(), Error> { + self.wait_efuse_idle(connection)?; + + let (conf_reg, conf_val, cmd_reg, cmd_val) = match self { + Chip::Esp32 => ( + efuse::esp32::defines::EFUSE_REG_CONF, + efuse::esp32::defines::EFUSE_CONF_READ, + efuse::esp32::defines::EFUSE_REG_CMD, + efuse::esp32::defines::EFUSE_CMD_READ, + ), + Chip::Esp32c2 => ( + efuse::esp32c2::defines::EFUSE_CONF_REG, + efuse::esp32c2::defines::EFUSE_READ_OP_CODE, + efuse::esp32c2::defines::EFUSE_CMD_REG, + efuse::esp32c2::defines::EFUSE_READ_CMD, + ), + Chip::Esp32c3 => ( + efuse::esp32c3::defines::EFUSE_CONF_REG, + efuse::esp32c3::defines::EFUSE_READ_OP_CODE, + efuse::esp32c3::defines::EFUSE_CMD_REG, + efuse::esp32c3::defines::EFUSE_READ_CMD, + ), + Chip::Esp32c5 => ( + efuse::esp32c5::defines::EFUSE_CONF_REG, + efuse::esp32c5::defines::EFUSE_READ_OP_CODE, + efuse::esp32c5::defines::EFUSE_CMD_REG, + efuse::esp32c5::defines::EFUSE_READ_CMD, + ), + Chip::Esp32c6 => ( + efuse::esp32c6::defines::EFUSE_CONF_REG, + efuse::esp32c6::defines::EFUSE_READ_OP_CODE, + efuse::esp32c6::defines::EFUSE_CMD_REG, + efuse::esp32c6::defines::EFUSE_READ_CMD, + ), + Chip::Esp32h2 => ( + efuse::esp32h2::defines::EFUSE_CONF_REG, + efuse::esp32h2::defines::EFUSE_READ_OP_CODE, + efuse::esp32h2::defines::EFUSE_CMD_REG, + efuse::esp32h2::defines::EFUSE_READ_CMD, + ), + Chip::Esp32p4 => ( + efuse::esp32p4::defines::EFUSE_CONF_REG, + efuse::esp32p4::defines::EFUSE_READ_OP_CODE, + efuse::esp32p4::defines::EFUSE_CMD_REG, + efuse::esp32p4::defines::EFUSE_READ_CMD, + ), + Chip::Esp32s2 => ( + efuse::esp32s2::defines::EFUSE_CONF_REG, + efuse::esp32s2::defines::EFUSE_READ_OP_CODE, + efuse::esp32s2::defines::EFUSE_CMD_REG, + efuse::esp32s2::defines::EFUSE_READ_CMD, + ), + Chip::Esp32s3 => ( + efuse::esp32s3::defines::EFUSE_CONF_REG, + efuse::esp32s3::defines::EFUSE_READ_OP_CODE, + efuse::esp32s3::defines::EFUSE_CMD_REG, + efuse::esp32s3::defines::EFUSE_READ_CMD, + ), + }; + + connection.write_reg(conf_reg, conf_val, None)?; + connection.write_reg(cmd_reg, cmd_val, None)?; + + // TODO: `esptool.py` says that if `EFUSE_ENABLE_SECURITY_DOWNLOAD` or + // `DIS_DOWNLOAD_MODE` was just set then we need to reconnect. It also + // uses `dlay_after_us=1000` on the `EFUSE_READ_CMD` write. + + self.wait_efuse_idle(connection)?; + + Ok(()) + } + + /// Check whether any errors occurred while writing the eFuse. + /// + /// Returns `Ok(true)` if write errors did occur. Returns `Err(_)` if we + /// failed to communicate with the chip. + fn efuse_write_failed( + self, + connection: &mut Connection, + block: EfuseBlock, + ) -> Result { + let Some(block_errors) = self.block_errors(block)? else { + // ESP32 chips can only detect write errors while using the 3/4 encoding scheme, + // in other cases the return value is meaningless. + if self.efuse_coding_scheme(connection, block)? != CodingScheme::_34 { + return Ok(true); + } + + let errors = connection.read_reg(efuse::esp32::defines::EFUSE_REG_DEC_STATUS)? + & efuse::esp32::defines::EFUSE_REG_DEC_STATUS_MASK; + + return Ok(errors != 0); + }; + + if block.index == 0 { + let (reg, count) = match self { + Chip::Esp32 => unreachable!(), + Chip::Esp32c2 => (efuse::esp32c2::defines::EFUSE_RD_REPEAT_ERR_REG, 1), + Chip::Esp32c3 => (efuse::esp32c3::defines::EFUSE_RD_REPEAT_ERR0_REG, 5), + Chip::Esp32c5 => (efuse::esp32c5::defines::EFUSE_RD_REPEAT_ERR0_REG, 5), + Chip::Esp32c6 => (efuse::esp32c6::defines::EFUSE_RD_REPEAT_ERR0_REG, 5), + Chip::Esp32h2 => (efuse::esp32h2::defines::EFUSE_RD_REPEAT_ERR0_REG, 5), + Chip::Esp32p4 => (efuse::esp32p4::defines::EFUSE_RD_REPEAT_ERR0_REG, 5), + Chip::Esp32s2 => (efuse::esp32s2::defines::EFUSE_RD_REPEAT_ERR0_REG, 5), + Chip::Esp32s3 => (efuse::esp32s3::defines::EFUSE_RD_REPEAT_ERR0_REG, 5), + }; + + let errors = (0..count) + .map(|idx| connection.read_reg(reg + (idx * 4))) + .collect::, _>>()?; + let any_errors = errors.into_iter().reduce(|a, b| a | b).unwrap() != 0; + + return Ok(any_errors); + } + + let EfuseBlockErrors { + err_num_reg, + err_num_mask: Some(err_num_mask), + err_num_offset: Some(err_num_offset), + fail_bit_reg, + fail_bit_offset: Some(fail_bit_offset), + } = block_errors + else { + unreachable!("eFuse block errors weren't set for a non-BLOCK0 block"); + }; + + let any_errors = connection.read_reg(err_num_reg)? & (err_num_mask << err_num_offset) + | connection.read_reg(fail_bit_reg)? & (1 << fail_bit_offset); + + Ok(any_errors != 0) + } + + /// TODO: documentation + pub fn write_efuse( + self, + connection: &mut Connection, + block: u32, + data: &[u8], + ) -> Result<(), Error> { + self.configure_efuse_write_timing(connection)?; + + let block = self.block(block)?; + if data.len() > (block.length as usize * 4) { + return Err(Error::WritingEfuseFailed(format!( + "Tried to write {} bytes to an eFuse of {} bytes", + data.len(), + block.length as usize * 4 + ))); + } + + // Apply coding scheme + let coded_data: Vec = { + let data = { + let mut buf = vec![0u8; block.length as usize * 4]; + buf[0..data.len()].copy_from_slice(data); + buf + }; + + let bytes = match self.efuse_coding_scheme(connection, block)? { + CodingScheme::None => data, + CodingScheme::_34 => { + return Err(Error::UnsupportedEfuseCodingScheme( + "3/4 coding is unimplemented".to_owned(), + )); + } + CodingScheme::ReedSolomon => reed_solomon::Encoder::new(12) + .encode(&data) + .iter() + .copied() + .collect(), + }; + + bytes + .chunks(4) + .map(|bytes| u32::from_le_bytes(bytes.try_into().unwrap())) + .collect() + }; + + // Write eFuse + let (conf_reg, conf_val, cmd_reg, cmd_val) = match self { + Chip::Esp32 => ( + efuse::esp32::defines::EFUSE_REG_CONF, + efuse::esp32::defines::EFUSE_CONF_WRITE, + efuse::esp32::defines::EFUSE_REG_CMD, + efuse::esp32::defines::EFUSE_CMD_WRITE, + ), + Chip::Esp32c2 => ( + efuse::esp32c2::defines::EFUSE_CONF_REG, + efuse::esp32c2::defines::EFUSE_WRITE_OP_CODE, + efuse::esp32c2::defines::EFUSE_CMD_REG, + efuse::esp32c2::defines::EFUSE_PGM_CMD | ((block.index as u32) << 2), + ), + Chip::Esp32c3 => ( + efuse::esp32c3::defines::EFUSE_CONF_REG, + efuse::esp32c3::defines::EFUSE_WRITE_OP_CODE, + efuse::esp32c3::defines::EFUSE_CMD_REG, + efuse::esp32c3::defines::EFUSE_PGM_CMD | ((block.index as u32) << 2), + ), + Chip::Esp32c5 => ( + efuse::esp32c5::defines::EFUSE_CONF_REG, + efuse::esp32c5::defines::EFUSE_WRITE_OP_CODE, + efuse::esp32c5::defines::EFUSE_CMD_REG, + efuse::esp32c5::defines::EFUSE_PGM_CMD | ((block.index as u32) << 2), + ), + Chip::Esp32c6 => ( + efuse::esp32c6::defines::EFUSE_CONF_REG, + efuse::esp32c6::defines::EFUSE_WRITE_OP_CODE, + efuse::esp32c6::defines::EFUSE_CMD_REG, + efuse::esp32c6::defines::EFUSE_PGM_CMD | ((block.index as u32) << 2), + ), + Chip::Esp32h2 => ( + efuse::esp32h2::defines::EFUSE_CONF_REG, + efuse::esp32h2::defines::EFUSE_WRITE_OP_CODE, + efuse::esp32h2::defines::EFUSE_CMD_REG, + efuse::esp32h2::defines::EFUSE_PGM_CMD | ((block.index as u32) << 2), + ), + Chip::Esp32p4 => ( + efuse::esp32p4::defines::EFUSE_CONF_REG, + efuse::esp32p4::defines::EFUSE_WRITE_OP_CODE, + efuse::esp32p4::defines::EFUSE_CMD_REG, + efuse::esp32p4::defines::EFUSE_PGM_CMD | ((block.index as u32) << 2), + ), + Chip::Esp32s2 => ( + efuse::esp32s2::defines::EFUSE_CONF_REG, + efuse::esp32s2::defines::EFUSE_WRITE_OP_CODE, + efuse::esp32s2::defines::EFUSE_CMD_REG, + efuse::esp32s2::defines::EFUSE_PGM_CMD | ((block.index as u32) << 2), + ), + Chip::Esp32s3 => ( + efuse::esp32s3::defines::EFUSE_CONF_REG, + efuse::esp32s3::defines::EFUSE_WRITE_OP_CODE, + efuse::esp32s3::defines::EFUSE_CMD_REG, + efuse::esp32s3::defines::EFUSE_PGM_CMD | ((block.index as u32) << 2), + ), + }; + + let mut err = None; + for _ in 0..3 { + self.wait_efuse_idle(connection)?; + + // Write the encoded data to the block's write address. + // + // The check value registers for the Reed-Solomon follow after the data + // registers. + for (idx, word) in coded_data.iter().enumerate() { + connection.write_reg(block.write_address + (idx as u32 * 4), *word, None)?; + } + + // Trigger the eFuse write and wait for the burning process to finish. + connection.write_reg(conf_reg, conf_val, None)?; + connection.write_reg(cmd_reg, cmd_val, None)?; + self.wait_efuse_idle(connection)?; + + // Clear the parameter registers to avoid leaking the programmed contents. + { + let words: u32 = if self == Chip::Esp32 { + // All ESP32 eFuse blocks have 8 data registers with no separate check + // registers. + 8 + } else { + // All other chips a shared set of 8 data registers and 3 check registers. + 8 + 3 + }; + for word in 0..words { + connection.write_reg(block.write_address + (word * 4), 0x00, None)?; + } + } + + // Trigger eFuse controller to update its internal registers. + self.trigger_efuse_register_read(connection)?; + + // Got at least one error, try burning the eFuse again. + if self.efuse_write_failed(connection, block)? { + let _ = err.insert("eFuse controller returned unreliable burn"); + continue; + } + + // Check that the bits we wrote are actually set. If there are any differences + // we perform the burn again. + for word in 0..block.length { + let rd_word = self.read_efuse_raw(connection, block.index.into(), word.into())?; + let wr_word = coded_data[word as usize]; + if (rd_word & wr_word) != wr_word { + let _ = err.insert("Not all bits were set after burning"); + continue; + } + } + + return Ok(()); + } + + // Reaching this point means that we failed to burn the eFuse 3 times in a row. + Err(Error::WritingEfuseFailed(err.unwrap().to_string())) + } +} + +#[cfg(feature = "serialport")] +#[derive(PartialEq)] +enum CodingScheme { + None, + _34, + ReedSolomon, +} + impl TryFrom for Chip { type Error = Error; diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index 0a49aae6..c63b4ae8 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -4,10 +4,14 @@ version = "0.0.0" edition = "2024" publish = false +[features] +efuse-generator = ["pyo3"] + [dependencies] chrono = "0.4" clap = { version = "4.5", features = ["derive"] } env_logger = "0.11" log = "0.4" +pyo3 = { version = "0.27.1", features = ["auto-initialize"], optional = true } serde = { version = "1.0", features = ["derive"] } serde_yaml = "0.9" diff --git a/xtask/src/efuse_generator.rs b/xtask/src/efuse_generator.rs index c389be96..78a5e287 100644 --- a/xtask/src/efuse_generator.rs +++ b/xtask/src/efuse_generator.rs @@ -1,6 +1,6 @@ use std::{ cmp::Ordering, - collections::{BTreeMap, HashMap}, + collections::HashMap, ffi::OsStr, fs::{self, OpenOptions}, io::{BufWriter, Write}, @@ -9,6 +9,12 @@ use std::{ }; use clap::{Args, Parser}; +use pyo3::{ + Bound, + PyAny, + prelude::{PyResult, Python}, + types::{PyAnyMethods as _, PyDict, PyList, PyModule, PyTuple}, +}; type Result = std::result::Result>; @@ -37,7 +43,7 @@ const HEADER: &str = r#" #![allow(unused)] -use super::EfuseField; +use super::{EfuseBlock, EfuseField}; "#; @@ -95,7 +101,7 @@ pub(crate) fn generate_efuse_fields(workspace: &Path, args: GenerateEfuseFieldsA let mut efuse_fields = parse_efuse_fields(&efuse_yaml_path)?; process_efuse_definitions(&mut efuse_fields)?; - generate_efuse_definitions(&espflash_path, efuse_fields)?; + generate_efuse_definitions(&espflash_path, &args.esptool_path, efuse_fields)?; Command::new("cargo") .args(["+nightly", "fmt"]) @@ -166,7 +172,11 @@ fn process_efuse_definitions(efuse_fields: &mut EfuseFields) -> Result<()> { Ok(()) } -fn generate_efuse_definitions(espflash_path: &Path, efuse_fields: EfuseFields) -> Result<()> { +fn generate_efuse_definitions( + espflash_path: &Path, + esptool_path: &Path, + efuse_fields: EfuseFields, +) -> Result<()> { let targets_efuse_path = espflash_path .join("src") .join("target") @@ -195,47 +205,190 @@ fn generate_efuse_definitions(espflash_path: &Path, efuse_fields: EfuseFields) - .trim_start() )?; - generate_efuse_block_sizes(&mut writer, &yaml.fields)?; + println!("Processing {chip}"); + generate_efuse_blocks(&mut writer, esptool_path, &chip)?; + generate_efuse_registers(&mut writer, esptool_path, &chip)?; generate_efuse_constants(&mut writer, &yaml.fields)?; } Ok(()) } -fn generate_efuse_block_sizes( - writer: &mut dyn Write, - fields: &HashMap, -) -> Result<()> { - let mut field_attrs = fields.values().collect::>(); - field_attrs.sort(); - - let block_sizes = field_attrs - .chunk_by(|a, b| a.block == b.block) - .enumerate() - .map(|(block, attrs)| { - let last = attrs.last().unwrap(); - let size_bits = last.start + last.len; - assert!(size_bits % 8 == 0); - - // not all bits for all blocks are defined, this is to avoid - // ending up with block sizes like 23 or 11 - // - // while this fixes the problem, it's not ideal to rely on this - (block, ((size_bits / 8).div_ceil(4)) * 4) - }) - .collect::>(); - - writeln!(writer, "/// Total size in bytes of each block")?; - writeln!( +fn generate_efuse_blocks(writer: &mut dyn Write, esptool_path: &Path, chip: &str) -> Result<()> { + write!( writer, - "pub(crate) const BLOCK_SIZES: &[u32] = &[{}];\n", - block_sizes - .values() - .map(|v| v.to_string()) - .collect::>() - .join(", ") + r#"/// All eFuse blocks available on this device. +pub(crate) const BLOCKS: &[EfuseBlock] = &["# )?; + python_definitions(esptool_path, chip, |_, mem_definition| { + let blocks = mem_definition + .getattr("EfuseDefineBlocks")? + .call0()? + .getattr("BLOCKS")?; + let blocks = blocks.cast::()?; + + let mut previous_index = None; + for block in blocks { + let block = block.cast::()?; + + let index: u8 = block.get_item(2)?.extract()?; + let length: u8 = block.get_item(7)?.extract()?; + let read_address: u32 = block.get_item(3)?.extract()?; + let write_address: u32 = block.get_item(4)?.extract()?; + + if let Some(previous_index) = previous_index { + assert!( + (previous_index + 1) == index, + "Block indices should be sequential" + ); + } else { + assert!(index == 0, "Block indices should start at 0"); + } + previous_index.replace(index); + + write!( + writer, + r#" + EfuseBlock {{ + index: {index}u8, + length: {length}u8, + read_address: {read_address:#x}u32, + write_address: {write_address:#x}u32, + }}, +"#, + )?; + } + + PyResult::Ok(()) + }) + .unwrap(); + + writeln!(writer, r#"];"#)?; + + Ok(()) +} + +fn generate_efuse_registers(writer: &mut dyn Write, esptool_path: &Path, chip: &str) -> Result<()> { + write!( + writer, + r#" +/// Defined eFuse registers and commands +pub(crate) mod defines {{ +"# + )?; + + python_definitions(esptool_path, chip, |inspect, mem_definition| { + let registers = mem_definition.getattr("EfuseDefineRegisters")?.call0()?; + + let members = inspect.getattr("getmembers")?.call((®isters,), None)?; + let members = PyDict::from_sequence(members.cast::()?)?; + let mut members: HashMap> = members.extract()?; + + { + write!( + writer, + " use super::super::EfuseBlockErrors; + pub(crate) const BLOCK_ERRORS: &[EfuseBlockErrors] = &[" + )?; + + let block_error_entry = |writer: &mut dyn Write, + err_num_reg: u32, + err_num_mask, + err_num_offset, + fail_bit_reg: u32, + fail_bit_offset| { + let map = |v: Option| { + v.map(|v| format!("Some({v:#x}u32)")) + .unwrap_or_else(|| "None".to_string()) + }; + writeln!( + writer, + " + EfuseBlockErrors {{ + err_num_reg: {err_num_reg:#x}u32, + err_num_mask: {}, + err_num_offset: {}, + fail_bit_reg: {fail_bit_reg:#x}u32, + fail_bit_offset: {}, + }},", + map(err_num_mask), + map(err_num_offset), + map(fail_bit_offset), + ) + }; + + if let Some(block_errors) = members.remove("BLOCK_ERRORS") { + for block_error in block_errors.cast::()? { + let (err_reg, err_num_mask, err_num_offset, fail_bit_offset): ( + u32, + Option, + Option, + Option, + ) = block_error.extract()?; + block_error_entry( + writer, + err_reg, + err_num_mask, + err_num_offset, + err_reg, + fail_bit_offset, + )?; + } + } else if members.contains_key("BLOCK_FAIL_BIT") + && members.contains_key("BLOCK_NUM_ERRORS") + { + // ESP32-C3 has a design flaw where the fail bit is shifted by one block, so its + // memory definition differs from the rest. + let num_errors = members + .remove("BLOCK_NUM_ERRORS") + .unwrap() + .cast_into::()?; + let fail_bit = members + .remove("BLOCK_FAIL_BIT") + .unwrap() + .cast_into::()?; + + for (num_errors, fail_bit) in num_errors.into_iter().zip(fail_bit.into_iter()) { + let (err_num_reg, err_num_mask, err_num_offset): ( + u32, + Option, + Option, + ) = num_errors.extract()?; + let (fail_bit_reg, fail_bit_offset): (u32, Option) = fail_bit.extract()?; + block_error_entry( + writer, + err_num_reg, + err_num_mask, + err_num_offset, + fail_bit_reg, + fail_bit_offset, + )?; + } + } + + writeln!(writer, " ];")?; + } + + for (name, value) in members { + if ["EFUSE_", "CODING_"] + .iter() + .any(|prefix| name.starts_with(prefix)) + { + let Ok(value) = value.extract::() else { + continue; + }; + + writeln!(writer, " pub(crate) const {name}: u32 = {value:#x};")?; + } + } + + PyResult::Ok(()) + }) + .unwrap(); + + writeln!(writer, "}}")?; + Ok(()) } @@ -246,6 +399,7 @@ fn generate_efuse_constants( let mut sorted = fields.iter().collect::>(); sorted.sort_by(|a, b| (a.1).cmp(b.1)); + writeln!(writer)?; for (name, attrs) in sorted { let EfuseAttrs { block, @@ -266,3 +420,20 @@ fn generate_efuse_constants( Ok(()) } + +fn python_definitions(esptool_path: &Path, chip: &str, f: F) -> PyResult<()> +where + F: FnOnce(Bound<'_, PyModule>, Bound<'_, PyModule>) -> PyResult<()>, +{ + Python::attach(|py| { + let sys = py.import("sys")?; + let path = sys.getattr("path")?; + path.call_method1("append", (esptool_path.as_os_str(),))?; + + let inspect = py.import("inspect")?; + + let mem_definition = py.import(format!("espefuse.efuse.{chip}.mem_definition"))?; + + f(inspect, mem_definition) + }) +} diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 36788dc5..5dde8104 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -3,6 +3,7 @@ use std::{env, path::PathBuf}; use clap::Parser; // Import modules +#[cfg(feature = "efuse-generator")] mod efuse_generator; mod test_runner; @@ -15,6 +16,7 @@ pub type Result = std::result::Result>; #[derive(Debug, Parser)] enum Cli { /// Generate eFuse field definitions + #[cfg(feature = "efuse-generator")] GenerateEfuseFields(efuse_generator::GenerateEfuseFieldsArgs), /// Run espflash tests @@ -49,6 +51,7 @@ fn main() -> Result<()> { }; match Cli::parse() { + #[cfg(feature = "efuse-generator")] Cli::GenerateEfuseFields(args) => efuse_generator::generate_efuse_fields(&workspace, args), Cli::RunTests(args) => test_runner::run_tests(&workspace, args), }